When does flush and clear commit?
Asked Answered
G

2

7

I'm using JPA EclipseLink 2.0 with Glassfish 3.1.2.2

I want to know if after I call

em.flush() 
em.clear()

The objects are immediatly commited to the database. My problem is I'm doing so many transactions that I'm getting OutOfMemory. I want to avoid this by flushing the transaction's objects.

After I flush and clear, I can't see any immediate entity commited to the database, I can only see them AFTER the whole process is done, which tells me this isn't actually commiting.

If flush and clear doesn't commit:

1) What does it actually do?

2) Why am I no longer getting OutOfMemory?

Please tell me if I'm right:

The objects that were allocated in my RAM are sent to the database, but changes are not yet commited. This only means I cleared my RAM, the objects are now in the DB server but the transaction is not yet commited.

Gainly answered 29/11, 2016 at 23:27 Comment(0)
E
8

Entities are synchronized to the connected database at transaction commit time. If you only have n = 1 ongoing transaction (here: JTA/container managed), changes on one or more entities get written to the DB the moment you call flush() on the EntityManager instance.

However, changes become "visible" only after the transaction has been properly executed by the container (here: Glassfish) which is responsible for transaction handling. For reference, see. section 7.6.1 (p. 294) of JPA Spec 2.0 which defines:

A new persistence context begins when the container-managed entity manager is invoked (Specifically, when one of the methods of the EntityManager interface is invoked) in the scope of an active JTA transaction, and there is no current persistence context already associated with the JTA transaction. The persistence context is created and then associated with the JTA transaction.

The persistence context ends when the associated JTA transaction commits or rolls back, and all entities that were managed by the EntityManager become detached.

In section 3.2.4 (Synchronization to the Database) of the JPA Spec 2.0 we find:

The state of persistent entities is synchronized to the database at transaction commit.

[..]

The persistence provider runtime is permitted to perform synchronization to the database at other times as well when a transaction is active. The flush method can be used by the application to force synchronization.

It applies to entities associated with the persistence context. The EntityManager and Query setFlushMode methods can be used to control synchronization semantics. The effect of FlushModeType.AUTO is defined in section 3.8.7. If FlushModeType.COMMIT is specified, flushing will occur at transaction commit; the persistence provider is permitted, but not required, to perform to flush at other times. If there is no transaction active, the persistence provider must not flush to the database.

Most likely in your scenario, the container (Glassfish) and/or your application is configured for FlushModeType.COMMIT(*1). In case FlushModeType.AUTO is in place, it is up to the Persistence Provider (EclipseLink) which "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." (Section 3.8.7, p. 122)

By contrast, the clear() method does NOT commit anything by itself. It simply detaches all managed entities from the current persistence context, thus causing any changes on entities which have not been flushed (committed) to get lost. For reference, see p. 70 of the linked JPA Spec.

With respect to the OutOfMemoryError, it's hard to tell what's causing this under which circumstances, as you did not provide much detail either. However, I would:

  1. read the aforementioned sections of the JPA specification
  2. check how your environment is configured and
  3. reevaluate how your application is written/implemented, potentially making false assumptions on the transaction handling of the container it is running in.

Related to 2., you might check your persistence.xml whether it configures

<property name="eclipselink.persistence-context.flush-mode" value="COMMIT" />

and change it to AUTO to see if there is any difference.

Hope it helps.

Footnotes

*1: But that's a good guess, as you did not provide that much detail on your setup/environment.

Erechtheus answered 4/12, 2016 at 8:18 Comment(1)
Great information. I want to explain why I was curious about this: I was using JTA but I also wanted to control when the transaction was commited. What I found is that I could "manually" control this (even with JTA) if I used @TransactionManagement(TransactionManagementType.BEAN) on top of my managed bean, and then use the UserTransaction. Any ways, this is what I asked and it was a very interesting and useful answer. Thanks.Gainly
L
0

On JPA transaction commit, JPA is doing flush automatically. You should see object in DB right after first transaction end, not only after whole process end. Check if really do more transactions or just one.

Laity answered 30/11, 2016 at 7:48 Comment(1)
I didn't mean multiple transactions, sorry. I meant multiple INSERTS in ONE transaction.Gainly

© 2022 - 2024 — McMap. All rights reserved.