Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring JPA entity lifecycle: managed changes and detached objects

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A JPA persistence context tracks managed entity identity and changes; an ordinary detached object no longer writes its field changes to the database.

Download Spring source kit

The downloadable Spring source kit pins Java 21 and Spring Boot 4.0.8 with its managed dependencies. Run mvn test to check the named fixture.

Observe the ownership transition

The stock fixture creates three accounts, then changes the first account through an EntityManager bound to a Spring JpaTransactionManager transaction. A fresh manager reads 80 after commit. The test does not call a repository save method because the object is already managed within that transaction.

The second test closes the manager before changing an account to seven. A fresh read still returns 100. Java object mutation happened, but database mutation did not. Keep that distinction visible when returning entities from a service; a caller holding an object is not evidence that its edits are being tracked.

Flush is not commit

The source kit assembles LocalContainerEntityManagerFactoryBean explicitly, scans only the isolated contract package and uses create-drop against a unique in-memory H2 database. This setup exists to test mapping behavior. Never turn that schema setting into a production migration strategy.

A flush can send changes to the database before commit, while the transaction can still fail or roll back. Query timing and transaction scope therefore matter even when code contains no explicit update call. Transaction boundaries and JDBC commit behavior are prerequisites for reasoning about these effects.

Checked source

Java
var transactions = new TransactionTemplate(new JpaTransactionManager(kit.factory));
transactions.executeWithoutResult(status -> {
    EntityManager manager = EntityManagerFactoryUtils.getTransactionalEntityManager(kit.factory);
    manager.find(JpaContracts.StockAccount.class, 1L).available = 80;
});

Test the boundary

JpaBoundaryTest.managedMutationFlushesOnCommit and detachedMutationDoesNotWriteItself checks this contract in the source kit. Excerpts belong to the named classes; use the downloadable files for imports, configuration and assertions.

Costs and boundaries

A context retains managed objects and provider bookkeeping until they are detached or the context closes. Loading n entities can retain O(n) application objects; SQL and dirty-check costs depend on mappings and the provider. The fixture verifies one update, not a bulk-import memory budget.

Common Mistakes

  • Do not confuse detached mutation with persistence.
  • Do not treat flush as successful commit.
  • Do not use create-drop for a deployed database.

Read next

Spring JPA fetch plans: measure N+1 queries before changing mappings, Spring JPA optimistic locking: reject a stale stock update, Spring TransactionTemplate: roll back a failed multi-row change, Java classes and objects.

Extend the tested workflow

Continue with Spring Data JPA repositories: derive a query from mapped properties.

spring
spring-boot
jpa-entity-lifecycle
Storage details