78

I have an EJB where I am saving an object to the database. In an example I have seen, once this data is saved (EntityManager.persist) there is a call to EntityManager.flush(); Why do I need to do this? The object I am saving is not attached and not used later in the method. In fact, once saved the method returns and I would expect the resources to be released. (The example code does this on a remove call as well.)

if (somecondition) {
    entityManager.persist(unAttachedEntity);
} else {
    attachedEntityObject.setId(unAttachedEntity.getId());
}
entityManager.flush();
buræquete
  • 14,226
  • 4
  • 44
  • 89
spartikus
  • 2,852
  • 4
  • 33
  • 38

5 Answers5

68

A call to EntityManager.flush(); will force the data to be persisted in the database immediately as EntityManager.persist() will not (depending on how the EntityManager is configured: FlushModeType (AUTO or COMMIT) by default is set to AUTO and a flush will be done automatically. But if it's set to COMMIT the persistence of the data to the underlying database will be delayed until the transaction is committed.

Denis Abakumov
  • 355
  • 3
  • 11
Benoit Wickramarachi
  • 6,096
  • 5
  • 36
  • 46
  • 16
    The description of `FlushModeType` is not correct: basically AUTO means that if you change an entity and afterwards make a SELECT query that may return that entity, AUTO will force the changes to that entity to be flushed before the SELECT execution. – V G Mar 16 '15 at 09:18
27

EntityManager.persist() makes an entity persistent whereas EntityManager.flush() actually runs the query on your database.

So, when you call EntityManager.flush(), queries for inserting/updating/deleting associated entities are executed in the database. Any constraint failures (column width, data types, foreign key) will be known at this time.

The concrete behaviour depends on whether flush-mode is AUTO or COMMIT.

Ypsilon
  • 122
  • 1
  • 9
Sachin Thapa
  • 3,559
  • 4
  • 24
  • 42
21

So when you call EntityManager.persist(), it only makes the entity get managed by the EntityManager and adds it (entity instance) to the Persistence Context. An Explicit flush() will make the entity now residing in the Persistence Context to be moved to the database (using a SQL).

Without flush(), this (moving of entity from Persistence Context to the database) will happen when the Transaction to which this Persistence Context is associated is committed.

Arun
  • 526
  • 4
  • 13
20

The EntityManager.flush() operation can be used the write all changes to the database before the transaction is committed. By default JPA does not normally write changes to the database until the transaction is committed. This is normally desirable as it avoids database access, resources and locks until required. It also allows database writes to be ordered, and batched for optimal database access, and to maintain integrity constraints and avoid deadlocks. This means that when you call persist, merge, or remove the database DML INSERT, UPDATE, DELETE is not executed, until commit, or until a flush is triggered.

Ataur Rahman Munna
  • 3,887
  • 1
  • 23
  • 34
  • 18
    The EntityManager.flush() operation can be used the write all changes to the database before the transaction is committed. -> This is not entirely true. You still need to commit, flush only sends the SQL statements to the database WITHOUT the commit. Triggering flush, without commit will still not actually INSERT any entities. commit will flush for you, if you have not flushed already, but flush will not commit.. – Koray Tugay Jul 06 '17 at 09:14
  • 7
    EntityManager.flush() will send the data to the database, but it will not become visible for others at this point. Instead, the changed database entries will get a row lock. But only after the commit() the changes become visible to others, and the locks are removed. – Thomas Schütt Nov 15 '17 at 16:21
  • 6
    @user2081279 Actually, the exact semantics depend on the effective transaction isolation setting: the defaults for this differ per database, and most databases offer various possible settings. – Frans May 05 '18 at 18:37
8

EntityManager.flush() sends actual SQL commands to DB.

Persistence framework usually manages transactions behind the scene. So there is no guaranty that flushed queries will be successfully committed.

EntityManager.flush() is always called just before the transaction commit by persistence framework automatically behind the scene.

EntityManager.persist() only registers an entity to persistence context without sending any SQL statements to DB. That means you won't get auto generated IDs after persist(). You just pass persisted object and eventually after later flush() it gets ID. You can call flush() yourself to get those IDs earlier. But again it is not the end of transaction so it can be rolled back and even more: changes might be seen (via phantom reads) by other transactions/thread/processes/servers and then disappear depending on DB engine and isolation level of current and foreign transaction!

gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • 1
    Thank you for the explanation! One addition though: I just tested this and EntityManager.persist() and EntityManager.flush() can BOTH get you auto generated IDs in a scenario, where you would not have an ID yet without EntityManager.persist(). Tested in a @Transactional annotated method with MySQL5InnoDBDialect (in case that matters) – Daniel Methner Nov 24 '21 at 12:13
  • So which method should I invoke to get the auto generated ID of an object is it flush or persist? If I cal em.persist I see that the object is saved in the database, flush too saves the object I am still confused – qualebs Aug 09 '22 at 07:40
  • @qualebs You definitely miss what is going in your app. Enable TRACE logging level and take attention to SQL statements & transactions. You use `flush()` to get IDs if transaction isn't closed (but no guaranty the commit succeeds later). If transaction is closed: it doesn't matter: Persistence Framework calls `flush()` behind the scene so you get those IDs anyway )) – gavenkoa Aug 09 '22 at 09:26