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

Spring Data JPA bulk update: the managed entity can still hold the old value

Last updated: 1 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

A JPQL update changes database rows without rewriting objects already held in the persistence context.

Keep the database and context apart

A reservation service loads a WarehouseBalance, then issues a repository update that marks the same SKU unavailable. The SQL changes a row, but the loaded entity can still report available=true. A later flush of that managed object may write stale state. An update count says how many database rows matched; it says nothing about synchronized Java objects. This is the boundary behind entity state and version checks.

Choose a deliberate cleanup

The repository method below flushes pending changes before the update and clears managed objects after it. That prevents the old balance instance from masquerading as fresh state, but every managed object becomes detached. The service must reload anything it needs afterward. Use a small transaction; do not clear a context holding unrelated, unflushed work. If the command needs entity callbacks or versioned writes, mutate the managed entity instead of using bulk JPQL.

Make the test inspect both views

Start a transaction, load one balance, run the bulk update, and assert the affected-row count and a fresh database read. Repeat with a managed object already present. The second assertion catches the stale-context failure that a repository-only test misses. This page is an implementation sketch; its exact mapping and SQL dialect need an application integration test.

Implementation sketch

Java
@Modifying(flushAutomatically = true, clearAutomatically = true)
@Query("update WarehouseBalance b set b.available = false " +
       "where b.tenantId = :tenantId and b.sku = :sku")
int disableSku(String tenantId, String sku);

Cost and verification

The bulk statement is one database update for the matching set, but clearing the context forces later reads to hydrate entities again. A per-entity path can cost more round trips while preserving lifecycle behavior.

Common Mistakes

  • Do not assume @Modifying refreshes previously loaded entities by default.
  • Do not enable clearAutomatically while relying on unrelated unflushed entities.
  • Do not use a bulk update when entity callbacks or optimistic version increments are part of the contract.

Read next

Spring JPA entity lifecycle: managed changes and detached objects, Spring JPA optimistic locking: reject a stale stock update, Spring Data JPA derived delete versus bulk delete: callbacks and memory cost, Spring TransactionTemplate: roll back a failed multi-row change.

spring
spring-boot
data-transactions
jpa-bulk-update-managed-state
Storage details