Audit Logging with @CreatedDate and @LastModifiedDate
Fast recall
Quick revision
Core answer
@Configuration class, define a `@MappedSuperclass` annotated with `@EntityListeners(AuditingEntityListener.class)` carrying `@CreatedDate`, `@LastModifiedDate`, `@CreatedBy`, and `@LastModifiedBy` fields, and implement `AuditorAwareSecurityContextHolder). Every entity that extends the superclass inherits auditing automatically. Use `Instant` for timestamps — UTC and unambiguous across server locations. The silent failure: forgetting @EnableJpaAuditing leaves all annotations inert with no error. Bulk @Modifying queries bypass the listener — set lastModifiedAt = CURRENT_TIMESTAMP explicitly in the JPQL. For full change history, layer Hibernate Envers on top.Practical Spring Data JPA feature knowledge and ability to avoid boilerplate by using framework capabilities
Using `@PrePersist`/`@PreUpdate` callbacks manually instead of Spring Data auditing, leading to duplicated code across entities
Discuss `Instant` vs `LocalDateTime` for timestamps, how `@EnableJpaAuditing` interacts with the ApplicationContext, and plugging the current user from Spring Security's `SecurityContextHolder` inside `AuditorAware`
Interview-ready guide
Interview answer
Spring Data JPA Auditing automates the bookkeeping that every entity needs. Setting it up correctly once in a @MappedSuperclass covers every entity in the application.
Setup:
- Add
@EnableJpaAuditingto a@Configurationclass - Create a
@MappedSuperclasswith the audit fields:@CreatedDate Instant createdAt@LastModifiedDate Instant updatedAt@CreatedBy String createdBy@LastModifiedBy String modifiedBy
- Extend this superclass in every entity
- Add
@EntityListeners(AuditingEntityListener.class)on the superclass
Providing the current user:
- Implement
AuditorAwareas a@Bean - Return
Optional.of(SecurityContextHolder.getContext().getAuthentication().getName())
`Instant` vs `LocalDateTime`:
Instantis always UTC — safe across timezonesLocalDateTimeis timezone-naive — different JVM TZ produces inconsistent values
When JPA auditing is not enough:
- Bulk
@Modifyingqueries skip the listener — set audit columns explicitly in JPQL - Async / scheduler contexts have no principal — propagate or set a system principal
- For full change history use Hibernate Envers; for downstream sync use CDC
Audit Logging with @CreatedDate and @LastModifiedDate
Direct Answer
Enable Spring Data JPA auditing with @EnableJpaAuditing on a @Configuration class, define a @MappedSuperclass annotated with @EntityListeners(AuditingEntityListener.class) carrying @CreatedDate, @LastModifiedDate, @CreatedBy, and @LastModifiedBy fields, and implement AuditorAware<T> to supply the current user (typically from SecurityContextHolder). Every entity that extends the superclass inherits auditing automatically. Use Instant for timestamps — UTC and unambiguous across server locations. The silent failure: forgetting @EnableJpaAuditing leaves all annotations inert with no error. Bulk @Modifying queries bypass the listener — set lastModifiedAt = CURRENT_TIMESTAMP explicitly in the JPQL. For full change history, layer Hibernate Envers on top.
Common Mistakes & Pitfalls
Using @PrePersist/@PreUpdate callbacks manually instead of Spring Data auditing, leading to duplicated code across entities
Check your understanding
Answer these without looking back at the article.
- How do you handle auditing in tests where there is no Spring Security context?
- What is the difference between `@MappedSuperclass` and `@Embeddable` for sharing audit fields?
- Can you use `@CreatedDate` without `@EnableJpaAuditing` — for example, using Hibernate's `@CreationTimestamp` instead?
- How does Hibernate Envers compare to writing to a custom audit table?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.