Jpa-2.0 – JPA – only the first submission fails, but all should fail
Please help me to explain the following (for me) very strange JPA behavior I deliberately change the primary key of entities prohibited in JPA
So first submit the correct exception Description: the attribute [date] of class [some. Package. Holiday] is mapped to the primary key column in the database. Update is not allowed
But the second (third, fourth,...) success! How is this possible?!
Holiday h1 = EM.find(Holiday.class,new GregorianCalendar(2011,3).getTime()); try { EM.getTransaction().begin(); h1.setDate(new GregorianCalendar(2011,4).getTime()); EM.getTransaction().commit(); System.out.println("First commit succeed"); } catch (Exception e) { System.out.println("First commit Failed"); } try { EM.getTransaction().begin(); EM.getTransaction().commit(); System.out.println("Second commit succeed"); } catch (Exception e) { System.out.println("Second commit Failed"); }
It will print out:
First commit Failed Second commit succeed
God, how is this possible?!
(use eclipse link 2.2.0.v2011022-r8913. In MySQL.)
Solution
The failure of the commit operation of the first transaction has nothing to do with the second transaction This is because the entitytransaction is no longer active when the first commit fails When you issue the second em.gettransaction() When begin invocation, a new transaction that does not know the first transaction will be started
It is worth noting that although your code can use the same entitytransaction reference in both cases, this class does not actually have to represent the transaction For eclipse link, the entitytransaction reference actually wraps an entitytransactionwrapper instance that further uses repeatableunitofwork. The latter two classes are implemented by eclipse link rather than provided by JPA The repeatablewriteunitofwork instance actually tracks the set of changes made by entities that will be merged into the shared cache (and database) When the first transaction fails, the underlying unitofwork is invalid, and a new unitofwork is created when the second entitytransaction is started
The same applies to most other JPA providers because the entitytransaction class is not a concrete final class On the contrary, it is an interface usually implemented by another class in the JPA provider. It may also wrap a transaction, requiring the client to use the entitytransaction reference instead of directly using the underlying transaction (possibly JTA transaction or resource local transaction)
In addition, you should remember:
> EntityTransaction. Begin() should only be called once Calling it again will cause an IllegalStateException to be thrown because it cannot be called when the transaction is active Therefore, you can call it a second time, which means that the first transaction is no longer active. > If the changes you require to be performed in the context of the first transaction are available for the second transaction, you must merge the entities back into the shared context in the second transaction after the first transaction is detached Although this may sound ridiculous, you should remember that before merging, the client (read, end user) can modify the separated entity, so the changes made by the end user may be retained, and errors (such as modification) can correct the primary key during the transition