Correct use of flush() in JPA/Hibernate
I was gathering information about the flush() method, but I'm not quite clear when to use it and how to use it correctly. From what I read, my understanding is that the contents of the persistence context will be synchronized with the database, i. e. issuing outstanding statements or refreshing entity data.
Now I got following scenario with two e开发者_运维知识库ntities A
and B
(in a one-to-one relationship, but not enforced or modelled by JPA). A
has a composite PK, which is manually set, and also has an auto-generated IDENTITY field recordId
. This recordId
should be written to entity B
as a foreign-key to A
. I'm saving A
and B
in a single transaction. The problem is that the auto-generated value A.recordId
is not available within the transaction, unless I make an explicit call of em.flush()
after calling em.persist()
on A
. (If I have an auto-generated IDENTITY PK then the value is directly updated in the entity, but that's not the case here.)
Can em.flush()
cause any harm when using it within a transaction?
Probably the exact details of em.flush()
are implementation-dependent.
In general anyway, JPA providers like Hibernate can cache the SQL instructions they are supposed to send to the database, often until you actually commit the transaction.
For example, you call em.persist()
, Hibernate remembers it has to make a database INSERT, but does not actually execute the instruction until you commit the transaction. Afaik, this is mainly done for performance reasons.
In some cases anyway you want the SQL instructions to be executed immediately; generally when you need the result of some side effects, like an autogenerated key, or a database trigger.
What em.flush()
does is to empty the internal SQL instructions cache, and execute it immediately to the database.
Bottom line: no harm is done, only you could have a (minor) performance hit since you are overriding the JPA provider decisions as regards the best timing to send SQL instructions to the database.
Can em.flush() cause any harm when using it within a transaction?
Yes, it may hold locks in the database for a longer duration than necessary.
Generally, When using JPA you delegates the transaction management to the container (a.k.a CMT - using @Transactional annotation on business methods) which means that a transaction is automatically started when entering the method and commited / rolled back at the end. If you let the EntityManager handle the database synchronization, sql statements execution will be only triggered just before the commit, leading to short lived locks in database. Otherwise your manually flushed write operations may retain locks between the manual flush and the automatic commit which can be long according to remaining method execution time.
Notes that some operation automatically triggers a flush : executing a native query against the same session (EM state must be flushed to be reachable by the SQL query), inserting entities using native generated id (generated by the database, so the insert statement must be triggered thus the EM is able to retrieve the generated id and properly manage relationships)
Actually, em.flush()
, do more than just sends the cached SQL commands. It tries to synchronize the persistence context to the underlying database. It can cause a lot of time consumption on your processes if your cache contains collections to be synchronized.
Caution on using it.
精彩评论