5

For synchronization and to retrieve the DB-generated ID's I feel coerced to call EntityManager.flush() at several places.

Performance implications aside, are there reasons not to call flush()?

In other words, is there any observable difference for the caller of my (DAO, ...) method if it does/doesn't flush()?

My scenario is in the context of a framework to support our JPA developers. I would provide some functionality which may or may not need to flush() somewhere deep in the call hierarchy. Will the user of these functions have to know if/when flushing occurs, or is it a private implementation detail without noticable effect to the caller?

JimmyB
  • 12,101
  • 2
  • 28
  • 44

2 Answers2

4

A call to flush() synchorizes the persistence context with the database. This is primarily required - if there needs to be a query hit (via JPQL etc).

Later in the call stack to the database, and if the persistence context contains a dirty value for any of the objects whose state could possibly be affected by query results, then those needs to be synchronized. In fact the default FlushModeType for JPA queries is AUTO

When queries are executed within a transaction, if FlushModeType.AUTO is set on the Query or TypedQuery object, or if the flush mode setting for the persistence context is AUTO (the default) and a flush mode setting has not been specified for the Query or TypedQuery object, the persistence provider is responsible for ensuring that all updates to the state of all entities in the persistence context which could potentially affect the result of the query are visible to the processing of the query. The persistence provider implementation may achieve this by flushing those entities to the database or by some other means.

So as long as you are querying the object via its state and not JPA queries and the results of those queries are not dependent on the dirty state, then it's bad for performance calling flush as it involves repeated dirty state check instead of just at commit time.

@Adams mentioned about his experience with OpenJPA where flush breaks few things, so I guess different implementations have problems here.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Shailendra
  • 8,874
  • 2
  • 28
  • 37
  • "querying the object via its state and not JPA queries" - What do you mean by "JPA queries"? `em.find(...)`, as opposed to `em.createQuery(...)`? – JimmyB Jun 09 '15 at 12:02
  • @Hanno - Yes exactly. The query has to hit the database and if there is a pending change in the form of dirty object state then there would be inconsistency if the synchronization is done late. – Shailendra Jun 09 '15 at 12:44
  • 1
    I think we're getting to an important point here: Even if I never flush explicitly, the JPA provider may decide/have to flush at some points, depending e.g. on what queries I perform and/or to what extent the provider can avoid hitting the DB with a read query. So, in essence, it's basically not predictable when in a sequence of read/write operations an implicit flush will occur. From that I conclude that I, too, may cause a flush at any point I find appropriate without violating any contract of JPA. – JimmyB Jun 09 '15 at 13:07
  • @HannoBinder yes, if for some reason query has AUTO flush mode, context can be flushed when you do not expect it. – AdamSkywalker Jun 10 '15 at 08:09
  • 2
    Apparently, even in [`COMMIT`](http://docs.oracle.com/javaee/6/api/javax/persistence/FlushModeType.html#COMMIT) flush mode, the "provider may flush at other times, but is not required to." – JimmyB Jun 10 '15 at 08:59
4

Performance pretty much sums up most of the reasons "not" to call flush. Flush is is a way to force all change statements to be pushed to the database immediately, rather than accumulate and be sent as a larger batch. It can be useful, as some transactions can be quite large and need to be cleared to release the memory, as well as to force a certain order for your updates to go into the database.

Other than performance and provider specific issues, the only other reason not to call flush is application specific, such as when some changes might violate a database constraint and require further modifications later on.

Chris
  • 20,138
  • 2
  • 29
  • 43
  • "when some changes might violate a database constraint" - But even if I never flush, there's no guarantee the data will *not* be flushed any time *before* commit, correct? – JimmyB Jun 09 '15 at 11:59
  • You can guarantee the data will not be flushed by not performing certain actions that would force a flush. FlushModeType.COMMIT also prevents the provider from deciding a query requires a flush to operate, and EclipseLink allows in-memory querying options that reduce the need for queries to flush data to see changes. – Chris Jun 09 '15 at 13:28
  • Re: FlushModeType.COMMIT - Looking at the [docs](http://docs.oracle.com/javaee/6/api/javax/persistence/FlushModeType.html#COMMIT) I found: "The provider *may flush at other times*, but is not required to." So no guarantee on that side. I'm starting to believe that explicit flushing should actually be ok at any time, because the provider itself may or may not implicitly flush at any time too. Thanks for your input. – JimmyB Jun 10 '15 at 08:56
  • Flushing is always ok, assuming your persistence unit is in a consistent state, but it is just a performance hit as the provider has to go through the model to calculate changes and persist them. The spec allows providers to flush when they may need, as an implementation is not required to cache changes - it might be valid for an implementation to generate insert/update/delete statements for each persist/merge/delete call. I don't know any providers to do that, but the spec was written to be as open as possible. – Chris Jun 10 '15 at 12:45