|
Actually my description in the prior comment is incorrect. The test case does the following:
1. EntityTransaction.begin() 2. getReference() on nonexistent record 3. rollback() in a business method 4. EntityManager.close(), which fails while running the detach algorithm IOW, short-circuiting close() won't fix the problem, as close() has only been called once. Additionally, on further inspection, EM.close() asserts that it's open before calling broker.close(), so there will never be multiple close() invocations. The problem does not occur in a JTA context, as the persistence context is coincident with the JTA transaction in that scenario, not the lifecycle of the EntityManager. It does not seem possible to disable the detach algorithm altogether. However, further investigation indicates that this is probably happening because OpenJPA is not clearing the persistence context during JPA rollback. From section 3.3.2 of the JPA spec: "For both transaction-scoped and extended persistence contexts, transaction rollback causes all pre-existing managed instances and removed instances[15] to become detached. The instances' state will be the state of the instances at the point at which the transaction was rolled back. Transaction rollback typically causes the persistence context to be in an inconsistent state at the point of rollback. In particular, the state of version attributes and generated state (e.g., generated primary keys) may be inconsistent. Instances that were formerly managed by the persistence context (including new instances that were made persistent in that transaction) may therefore not be reusable in the same manner as other detached objects—for example, they may fail when passed to the merge operation.[16]" Resolving this discrepancy will address the case that I'm looking at in particular, but will not address the case where the getReference() method is invoked outside a transaction but in an extended persistence context. New approach: I am going to change OpenJPA's detach algorithms to handle failures more gracefully, and back out the patch I mentioned earlier. This will resolve the unexpected exceptions I was seeing.
Separately, Resolved with svn 497185.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The use case at hand seems to do the following:
1. UserTransaction.begin()
2. getReference() on a nonexistant record
3. close() in a session bean
4. UserTransaction.commit(), which fails
With the patch, BrokerImpl.afterCompletion() calls BrokerImpl.free(Status.STATUS_ROLLEDBACK) from line 1789, because close had been invoked. The patch makes that free() invocation work as expected.
However, close() is being invoked later on. This later invocation is probably erroneous, but currently it is causing OpenJPA to throw an exception from BrokerImpl.java:3984, because close() calls free() with Status.NO_TRANSACTION.
I believe that OpenJPA should be short-circuiting close() if isClosed() returns true, or that free() should short-circuit if isClosed() returns true.