52

What should I prefer when updating the database? What are the pros & cons with either method and when shall I use the one or the other?

public void disemployEmployee(Integer employeeId, Date endDate) {
    Employee employee = (Employee)em.find("Employee", employeeId);
    employee.getPeriod().setEndDate(endDate);
    em.flush();
}

public void disemployEmployee(Integer employeeId, Date endDate) {
    Employee employee = (Employee)em.find("Employee", employeeId);
    em.getTransaction().begin();
    employee.getPeriod().setEndDate(endDate);
    em.getTransaction().commit();
}
Rox
  • 2,647
  • 15
  • 50
  • 85

5 Answers5

57

In your first example, the changes to the data are reflected in database after encountering flush, but it is still in transaction.

But in second example, you are committing transaction immediately. Therefore the changes are made into the database & transaction also ends there.

Sometimes, flush may be useful to persist the data in between the ongoing transaction & then finally commit the changes afterwards. So you can also rollback the previous changes if there occurs some problem afterwards, like for batch insert/update.

Ahmad Hosny
  • 597
  • 1
  • 6
  • 23
Nayan Wadekar
  • 11,444
  • 4
  • 50
  • 73
  • 9
    In the first example there is no transaction, so there is an exception thrown at flush(). – DataNucleus Jun 15 '12 at 10:20
  • 2
    @DataNucleus I think in CMT, we don't have to start/end transaction manually. – Nayan Wadekar Jun 15 '12 at 10:23
  • 2
    sure but is he in CMT ? in his other example he starts the txn, so that is the only assumption I can make – DataNucleus Jun 15 '12 at 10:33
  • @DataNucleus I presume in 1st case, transaction is implicitly commited & in 2nd its explicitly. – Nayan Wadekar Jun 15 '12 at 10:49
  • 1
    @NayanWadekar I don't think the data is send to the database. It's only in the cache. You need to "commit" to send data. – sguan Oct 18 '15 at 17:37
  • @TheProgrammer Which case are you referring. Do you mean that flush only caches data & not persisted, then it's wrong. Flush persists data, but isn't committed, can be rolled back. – Nayan Wadekar Oct 19 '15 at 16:36
  • @nayanwadekar I mean the first example. He only flushed but didn't commit which won't be loaded to the database. – sguan Oct 20 '15 at 00:50
  • 2
    @TheProgrammer No, changes are reflected immediately on flush, refer documentation - https://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#flush() & here is some explanation about it - http://stackoverflow.com/a/17703822 – Nayan Wadekar Oct 20 '15 at 04:10
  • @NayanWadekar then what about these: http://stackoverflow.com/questions/8863725/how-we-can-get-jpa-entitymanager-flush-work, http://stackoverflow.com/questions/4275111/correct-use-of-flush-in-jpa-hibernate – sguan Oct 21 '15 at 03:22
  • @NayanWadekar Thanks for telling me about this. I appreciate it! – sguan Oct 22 '15 at 04:32
  • "Sometimes, flush may be useful to persist the data in between the ongoing transaction & then finally commit the changes afterwards." If flush immediatly changes db, why would I commit later? – Koray Tugay Jul 30 '16 at 06:37
  • @KorayTugay Read next line to it. – Nayan Wadekar Aug 01 '16 at 11:53
19

According to the javadoc for flush and commit, flush is only for use within a transaction. It flushes (but doesn't commit), whereas commit commits data (obviously). They are distinct; there is no "preference" to be had.

The first example is wrong, and should result in an exception on calling flush (TransactionRequiredException).

E_net4
  • 27,810
  • 13
  • 101
  • 139
DataNucleus
  • 15,497
  • 3
  • 32
  • 37
  • 1
    What can I do with flush() that I cannot do without using flush()? – Rox Jun 15 '12 at 09:55
  • 1
    Flush puts the data in the datastore, and without it the data isn't there so queries can return data that is stale. Perhaps read the JPA spec on flush() – DataNucleus Jun 15 '12 at 10:19
  • 3
    Well, everything the API says about flush() is "Synchronize the persistence context to the underlying database" and I have never used it before but my transactions still puts the data to database when calling `EntityManager.getTransaction.commit()`. And I have not called EntityManager.flush()! So I cannot understand the use of flush() when you can do everything it does even without it. – Rox Jun 15 '12 at 10:32
  • 8
    Yes indeed commit commits the data (as already said), and to do that, if it hasn't been flushed to the datastore then it does the flush. flush() simply gives you the option of putting it there earlier. – DataNucleus Jun 15 '12 at 10:35
  • 6
    One use case for flush() is to force the generation of an ID you can use within the same transaction. For example, when you want to create logs (within the database) or history entries (basically copies). The reason not to use relationships between those entries and the actual entity in which case you don’t have to bother with the IDs is because you then couldn’t delete the entity without losing the log/history entry due to foreign keys. – Martin Jan 02 '15 at 11:17
5

Both of your code samples doesn't persist or merge the entity state to be written to DB.

I don't think it appropriate to compare EntityManager.flush() and EnityManager.EntityTransaction.commit().

flush() MUST be enclosed in a transaction context and you don't have to do it explicitly unless needed (in rare cases), when EntityTransaction.commit() does that for you.

Refer this link Is it necessary to call a flush() (JPA interface) in this situation?

Refer this link Question about flushing with JPA before a query is called for a scenario to use flush()

Community
  • 1
  • 1
Ahamed Mustafa M
  • 3,069
  • 1
  • 24
  • 34
0

I would go for container managed transaction whenever possible. Bean managed transactions usually require significantly more code, because of the Exception possibilities. Also, it's more error prone (rollbacks, resource management).

That said, I would use a flush after the commit in container managed mode. That way I can catch possible PersistenceExceptions in my storage module and convert it to some more meaningful Exception for my use case module. This because I don't want to handle storage-specific Exceptions here, because I might swap the storage module out for something that does not use JPA... which never happened to me :)

Dormouse
  • 1,617
  • 1
  • 23
  • 33
0

I think the missing part is, flush() just add to the datasources to be ready to commit, gives actual ids but not persist by default.

So if you need flush() to work as commit() you need to set the flush mode to Commit in the EntityManager by:

void setFlushMode(FlushModeType flushMode)
Set the flush mode that applies to all objects contained in the persistence context.

Note that FlushModeType is an enum that has these two values:

FlushModeType AUTO (Default) Flushing to occur at query execution. Since: JPA 1.0 FlushModeType COMMIT Flushing to occur at transaction commit. The provider may flush at other times, but is not required to. Since: JPA 1.0

I hope this help

Mariam A. Moustafa
  • 165
  • 1
  • 2
  • 14