EntityManager.setFlushMode与Query.setFlushMode执行顺序差异疑问
Let me break down the root cause of this confusing behavior you're seeing, using your test cases and JPA/EclipseLink specifics.
First, Recap Your Test Scenario
You have two test cases where:
- The EntityManager's FlushMode is set to
COMMIT - The Query's reported FlushMode is
AUTOin both cases
But the SQL execution order is reversed, leading to different final persisted values:
- Explicitly set Query to AUTO: SQL runs as
flush entity update (AAA) → execute JPQL update (BBB) → commit→ final value is BBB - Use Query's default AUTO: SQL runs as
execute JPQL update (BBB) → flush entity update (AAA) → commit→ final value is AAA
The Key Difference: Default vs. Explicitly Set Query FlushMode
Even though query.getFlushMode() returns AUTO in both scenarios, EclipseLink handles these two cases differently under the hood, which aligns with JPA spec nuances but has a non-obvious implementation:
1. Explicitly setting query.setFlushMode(FlushModeType.AUTO)
When you explicitly set the Query's FlushMode, it ignores the EntityManager's FlushMode entirely, strictly following the JPA spec for AUTO:
AUTO: Flush is triggered when executing a query
This means EclipseLink will flush all pending changes in the persistence context (your e.setName("AAA") modification) before executing the JPQL update statement. Hence the SQL order you see in test case 1.
2. Using the Query's default "AUTO" FlushMode
When you don't explicitly set the Query's FlushMode, the reported AUTO is just a default return value from the API. Internally, EclipseLink makes the Query inherit the EntityManager's FlushMode (COMMIT in your case).
Per the JPA spec for COMMIT:
COMMIT: Flush is triggered only when the transaction is committed
So the JPQL update runs first, and the pending entity change (AAA) is only flushed when the transaction commits—after the JPQL update. That's why the SQL order is reversed in test case 2.
Confirming This Behavior
To verify, you can reference EclipseLink's implementation logic:
- The
Query.getFlushMode()method returnsAUTOby default even if the actual behavior inherits from the EntityManager. - Only an explicit call to
query.setFlushMode()overrides this inheritance and enforces the specified FlushMode regardless of the EntityManager's setting.
Summary
The confusion comes from the discrepancy between the reported FlushMode (via getFlushMode()) and the actual runtime behavior:
- Explicitly setting
AUTOon the Query forces it to flush before execution, ignoring the EntityManager. - The default "AUTO" setting on the Query is a placeholder—its actual behavior follows the EntityManager's FlushMode.
This is an EclipseLink-specific implementation detail that aligns with the JPA spec's flexibility around default FlushMode inheritance.
内容的提问来源于stack exchange,提问作者energize-cactus

