JPA Auditing으로 인한 Mock Data 날짜 설정 오류

Kim jisu·2025년 7월 23일
0

 Debugging Note

목록 보기
32/37

1. 목적

  • “지난 한 달간 인기 상품 Top 3” 기능을 위한 실제 주문 빈도 기반 샘플 데이터 생성
  • JPA Auditing(@CreatedDate)에 의해 강제 갱신되는 created_at 필드를 직접 제어하여, 과거 시점의 주문을 DB에 삽입

2. 배경

  1. 초기 시도

    • DataInitializer에서 리플렉션으로 Order 엔티티의 createdAt 필드 세팅
    • orderRepository.save(order) 호출
  2. 문제 발생

    • JPA Auditing이 @CreatedDate 어노테이션을 기반으로 항상 현재 시각으로 덮어씀
    • 리플렉션 설정값이 반영되지 않음

3. 원인 분석

  • Spring Data JPA의 AuditingEntityListener

    • 엔티티 저장 직전에 @CreatedDate 필드에 자동으로 현재 시각을 주입
    • 리플렉션, 수동 세팅 모두 Auditing 우선순위에 밀려 무시됨

4. 해결 방안 검토

방안장점단점
1) Auditing 비활성화(실행 컨텍스트 내)JPA 사용 유지
간단 설정
애플리케이션 전체 영향 가능성
소스 코드·설정 추가 필요
2) 별도 엔티티 매니저/Repository 사용Auditing 적용 안 함
JPA API 호환
설정 복잡
관리 부담
3) JdbcTemplate 직접 SQL 삽입Auditing 완전 우회
SQL로 원하는 값 바로 삽입
SQL 하드코딩
Entity 일관성 주의 필요

3번 선택: 간단하고 확실하게 Auditing을 우회


5. 구현 내용

  1. 의존성 추가

    <!-- build.gradle 예시 -->
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
  2. JdbcTemplate 빈 주입

    @Component
    public class DataInitializer {
        private final JdbcTemplate jdbcTemplate;
        public DataInitializer(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
        // ...
    }
  3. createOrderWithTimestamp() 메서드 변경

    private void createOrderWithTimestamp(Long userId, Long productId, int quantity, LocalDateTime createdAt) {
        String sql = "INSERT INTO orders (user_id, product_id, quantity, created_at, updated_at, created_by, updated_by) " +
                     "VALUES (?, ?, ?, ?, ?, ?, ?)";
        jdbcTemplate.update(sql,
            userId,
            productId,
            quantity,
            Timestamp.valueOf(createdAt),   // 직접 설정한 과거/현재 시각
            Timestamp.valueOf(createdAt),   // updated_at도 동일하게
            "system",                        // created_by
            "system"                         // updated_by
        );
    }
  4. 샘플 데이터 분포

    • A-ECG: 최근 30일 내 15건
    • CLtime+: 최근 30일 내 10건
    • CLCheckUp: 최근 30일 내 7건
    • 역사적 데이터: 45~60일 전 주문 여러 건
  5. Auditing 어노테이션 유지 여부

    • 유지해도 무관, JdbcTemplate은 Auditing을 거치지 않으므로 영향 없음

6. 결과 검증

  1. DB 직접 조회

    SELECT product_id, COUNT(*) AS cnt
    FROM orders
    WHERE created_at BETWEEN NOW() - INTERVAL '30' DAY AND NOW()
    GROUP BY product_id
    ORDER BY cnt DESC
    LIMIT 3;
profile
Dreamer

0개의 댓글