9

We are working on a little web (will run on Tomcat) with the data layer done with JPA (Eclipselink). I did similar thing some time ago. But i were always unsure when i need to begin and end transactions or do a flush. At the moment i use transaction if i add (persist) and remove objects. If i call setters on an already persisted object i do not use transactions.

Is there a guide/ tutorial or a short answer when to use transactions or how to implement application managed JPA correctly.

Ashot Karakhanyan
  • 2,804
  • 3
  • 23
  • 28
dermoritz
  • 12,519
  • 25
  • 97
  • 185

1 Answers1

14

I think one can summarize an answer to your question. almost any JPA operation needs a transaction, except find/selects that do not lock entities (i.e any JPA operation that does not change the data).

(JTA transaction-scoped entity manager) In the case of an JTA transaction-scoped entity manager it is better to quote from the spec (Chapter 3 Entity Operations):

The persist, merge, remove, and refresh methods must be invoked within a transaction context when an entity manager with a transaction-scoped persistence context is used. If there is no transaction context, the javax.persistence.TransactionRequiredException is thrown.

Methods that specify a lock mode other than LockModeType.NONE must be invoked within a transaction context. If there is no transaction context, the javax.persistence.TransactionRequiredException is thrown.

The find method (provided it is invoked without a lock or invoked with LockModeType.NONE) and the getReference method are not required to be invoked within a transaction context. If an entity manager with transaction-scoped persistence context is in use, the resulting entities will be detached; if an entity manager with an extended persistence context is used, they will be managed. See section 3.3 for entity manager use outside a transaction.

(Application-managed/resource-local entity manager) In the case of an Application-managed entity manager, the JPA spec is not clear about the behavior. In the case of Hibernate, it is pretty complicated what happens, when not inside a transaction (it could depend also on the JDBC driver and the autocommit mode of the DB connection). Check Hibernate's article on this theme. Basically you are strongly encouraged to always use transactions for the above mentioned operations.

To the second part of your question: if you called a setter of a managed entity, and without flushing you detached it (i.e before transaction commit), the behavior is unclear/undefined, i.e you should better correct the code.

Example of buggy code:

//begin Transaction
MyEntity entity = em.find(MyEntity.class, 1L);
entity.setField("New value");
em.detach();//it is not sure whether the "New value" will be persisted. To make sure it is persisted, ypu need to call em.flush() before detaching
//commit Transaction

Usually if the order of DB operations (not the same as the order of enity manager operations) is not important, you can leave the JPA implementation to decide when to flush (e.g on transaction commit).

Community
  • 1
  • 1
V G
  • 18,822
  • 6
  • 51
  • 89
  • So for setters i need flush but i do not need begin/end transaction? But why to flush? As i read here and there, it seems that flush empties the sql-command cache (execute all operations immediately), but why not let JPA-Implementation decide when to execute? – dermoritz Feb 10 '14 at 11:00
  • so the code is ok if no em.detach() is called? not buggy code: MyEntity entity = em.find(MyEntity.class, 1L); entity.setField("New value"); – dermoritz Feb 10 '14 at 11:49
  • Yes, of course. That is a "usual situation". flush will be called automatically on transaction commit :) – V G Feb 10 '14 at 11:52
  • in my case the setter worked without transaction and without "detach" - why do i need transaction here? – dermoritz Feb 10 '14 at 13:02
  • It worked probably because a transaction was automatically started and committed for you (e.g in Spring @Transactional methods or EJBs). If that is your case, that it explains everything and of course you do not need to open any transactions. Was your persistence unit JTA or resource local? – V G Feb 10 '14 at 13:29
  • I do use normal application managed jpa (resource local) in a simple unit test. And all setters work fine and data is updated in db without transactions. A coworker said that transactions are needed but i remembered from a former project that setters work directly - and o we asked here. – dermoritz Feb 11 '14 at 10:41
  • 2
    From my experience: although the JPA spec requires a transaction and says that an TransactionRequiredException should be thrown if no transaction is bound to the session (for those mentioned operations), in the case of a resource local entity manager no Exception is thrown (e.g it was Hibernate in a JAVA EE context). Anyway, could you post a bit of your code? Also, it is really recommended to work with transactions in all those cases when you change the data. Also try disabling the autocommit mode of your persistence provider (ElipseLink in your case) in order to enforce transactions. – V G Feb 11 '14 at 11:10
  • 1
    Also check this article about the behavior when no explicit transaction boundaries are set: https://community.jboss.org/wiki/Non-transactionalDataAccessAndTheAuto-commitMode (ElipseLink should behave similarly) – V G Feb 11 '14 at 11:59