updatedAt 필드를 자동으로 관리하는 방법 2가지
- JPA Auditing의 @LastModifiedDate: 엔티티가 변경될 때 JPA가 Java 객체의 필드를 수정
- DB의 ON UPDATE CURRENT_TIMESTAMP: DB에서 직접 updated_at 값을 자동 변경
이 둘을 동시에 사용하면 시간 값이 충돌하거나 예상치 못한 동작이 발생할 수 있다.
발생 가능한 문제
문제 유형 | 설명 |
값 불일치 | 애플리케이션에서 설정한 @LastModifiedDate 값과 DB에서 자동 설정한 값이 다를 수 있음 |
엔티티 변경 감지 실패 | DB에서 자동 갱신한 값이 영속성 컨텍스트에 반영되지 않아 dirty checking에 영향을 줄 수 있음 |
무한 업데이트 루프 | DB에서 업데이트된 시간 값으로 인해, 엔티티가 계속 변경되었다고 인식되어 저장을 반복할 수 있음 (특히 auditing + dirty checking 같이 쓸 때) |
JPA Auditing 무력화 | @LastModifiedDate로 설정된 값이 persist 되기 전에 DB에서 다른 값으로 덮어쓸 수 있음 |
해결 방법 및 권장 사항
1. 둘 중 하나만 사용하기
- Spring Auditing만 사용
- @LastModifiedDate를 활용하고, DB 제약 조건 제거
- 모든 시간 변경은 Java 측에서 통제
- DB 제약 조건만 사용
- @LastModifiedDate 제거하고, ON UPDATE에 맡김
- DB에서 시간 통제 (e.g., 외부 시스템과 통합되어 DB 레벨 제약 필요 시)
2. JPA에서 DB 트리거 무시하기
- DB에서 ON UPDATE CURRENT_TIMESTAMP를 쓰되, JPA에서는 해당 필드를 insertable = false, updatable = false로 설정
@Column(name = "last_modified", insertable = false, updatable = false)
private LocalDateTime lastModified;
Spring Auditing vs DB 제약 조건
구분 | Spring Auditing (@LastModifiedDate) | DB 제약 조건 (ON UPDATE CURRENT_TIMESTAMP) |
적용 위치 | 애플리케이션(Java) | 데이터베이스(MySQL 등) |
테스트 용이성 | ✅ 시간 mocking 가능, 단위 테스트 친화적 | ❌ DB 의존, mocking 어려움 |
시간 정확성 | ❌ 서버 시간 기준 (NTP 불일치 시 문제 가능) | ✅ DB 시간 기준으로 일관성 보장 |
외부 시스템 호환성 | ❌ 외부에서 직접 DB 수정 시 시간 불일치 우려 | ✅ DB가 시간 통제 → 일관성 유지 |
유지보수성 | ✅ Java 코드로 제어 가능, DB 종속 낮음 | ❌ DB마다 문법 상이 → 이식성 낮음 |
클라우드/이식성 | ✅ DB 트리거 없이 어디서나 동일 동작 | ❌ 특정 DB에 종속됨 (예: MySQL 전용 문법) |
엔티티 일관성 | ✅ 엔티티 변경과 시간 갱신이 함께 처리됨 | ❌ DB가 시간 설정하므로 엔티티 객체엔 반영 안 됨 |
무결성 보장 | ❌ 애플리케이션 오류 시 잘못된 시간 저장 가능 | ✅ DB 단독으로 보장됨 (신뢰성 높음) |
사용 권장 시점 | - Spring 기반 단일 애플리케이션 - 테스트/이식성 중시 - 도메인 중심 설계 |
- 외부 시스템과 DB 공유 - 데이터 신뢰성/무결성 중요 - 레거시 또는 DB 중심 구조 |
시스템의 구조와 요구사항에 따라 한 가지 방식을 선택하고 일관성 있게 적용하는 것이 중요하다 !
- 애플리케이션 중심의 설계와 테스트 용이성을 중시한다면 → @LastModifiedDate
- 데이터 무결성과 외부 시스템과의 통합이 핵심이라면 → ON UPDATE CURRENT_TIMESTAMP
'Spring > 문제 해결 (Troubleshooting)' 카테고리의 다른 글
@ControllerAdvice가 Filter 예외를 잡지 못하는 문제 해결 (0) | 2025.06.04 |
---|---|
Spring Security 에러 핸들링 오류 해결, /error 접근 권한 문제 (0) | 2025.05.29 |
JPA 변경사항이 즉시 반영되지 않을 때 - 영속성 컨텍스트와 DB 값 불일치 문제 (2) | 2025.05.23 |
Caused by: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName. (0) | 2025.05.12 |
406 Not Acceptable - responseDTO @Getter 의 중요성 (3) | 2025.05.09 |