Definitions
Entity Lifecycle: Sequence of states entity goes through: Transient, Managed, Detached, Removed. Each state determines persistence behavior.
Transient: Entity not associated with persistence context. No database identity. Created with new keyword, not persisted.
Managed: Entity associated with active persistence context. Changes automatically tracked, persisted on transaction commit. Returned from repository.find*() methods.
Detached: Entity previously managed but context closed. Changes not tracked. Can be reattached via merge().
Removed: Entity marked for deletion. Persisted as deletion on commit.
Persistence Context: Cache of managed entities for current transaction. Ensures single instance per entity ID, tracks changes.
@PrePersist / @PostPersist: Lifecycle callbacks executed before/after entity insertion. Used for initialization, auditing.
@PreUpdate / @PostUpdate: Callbacks before/after updates.
Q&A
What are the entity lifecycle states?
- Transient (new, unassociated with database),
- Managed (associated with persistence context, changes tracked),
- Detached (previously managed, context closed),
- Removed (marked for deletion).
Understanding states is crucial for knowing when data persists, when changes tracked. Transitions occur via entityManager operations.
When does an entity transition from transient to managed?
Transition occurs when entity saved: entityManager.persist(entity) or repository.save(entity). Entity gets database ID, managed by persistence context. Changes tracked automatically within transaction.
How do you reattach a detached entity?
Use entityManager.merge(detachedEntity) or repository.save(detachedEntity). Returns managed instance; updates not on detached object. Alternative: keep persistence context open or use refresh().
What’s the difference between persist() and merge()?
persist() inserts new entity, returns void. merge() handles both insert (if new) and update (if detached), returns managed instance. Use persist() for new entities, merge() for reattaching. merge() safer for mixed scenarios.
What are lifecycle callbacks and when use them?
Callbacks execute at entity lifecycle events: @PrePersist (before insert), @PostPersist (after insert), @PreUpdate (before update), @PreRemove (before delete). Use for automatic auditing (set timestamps, user info), validation, or cleanup. Define as methods annotated with callbacks.
What happens if you modify a managed entity?
Changes automatically tracked within transaction; persisted on commit without explicit save(). This is powerful but can cause surprises if not understood. Be careful; unexpected changes persist.
Code Examples
Example - Entity Lifecycle:
@Entity
@Data
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@CreationTimestamp
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}Example - Transient to Managed:
// Transient - new, not in context
User user = new User("Alice");
System.out.println(user.getId()); // null
// Managed - after save
User managed = repository.save(user);
System.out.println(managed.getId()); // database ID assignedExample - Detached to Managed:
User user = repository.findById(1L).get(); // Managed
// Context closed or flush occurred
// User now detached
user.setName("Updated"); // Change not tracked
User reattached = repository.save(user); // Reattached, merged
System.out.println(reattached.getName()); // "Updated"Key Points
- Persistence Context: Session/transaction scope; same entity ID returns same instance (first-level cache).
- Lazy Exceptions: Access lazy collection outside transaction causes LazyInitializationException; load data within transaction.
- Dirty Checking: Managed entities automatically flushed on transaction commit; no explicit save needed for updates.
- Cascading: Configure cascade types carefully; cascading deletes can unintentionally remove related entities.