users@jpa-spec.java.net

[jpa-spec users] Issue with JTA and JPA interaction

From: Christian Romberg <cromberg_at_versant.com>
Date: Tue, 19 Jun 2012 09:40:23 +0200

Hi Paul, all,

Recently we came across an issue regarding the interaction of JTA and JPA.

The user visible artifact of JPA is an instance of EntityManager. JPA
standardizes
ORMs, so without loss of generality we can assume, that the EntityManager
uses a
JDBC connection to access the database, and with respect to this issue, we
can
also assume, that the JDBC driver used supports XADataSource.

(Note, that the association of JDBC Connection instance to EntityManager
instance is
generally not mandated by the JPA spec (although for certain points in time
it is implied).
This means, it is permitted for the JPA vendor (unless database locks are
used) to use a different
JDBC connections for every database read operation, and return them to the
pool after use.

If database locks are used for operations and/or if flushing occurs, then
of course the JDBC connection
needs to be pinned to the EntityManager instance to guarantee transactional
semantics.)

The intended JPA-JTA interaction is as follows:

The JPA implementation does _not_ interact with XADataSources,
XAConnections or XAResources,
it _does_ use a JDBC connection pool to acquire it's JDBC connections. This
pool is configured to return
enlisted connections, and when the JPA implementation asks for a
connection, the container in the
background acquires an XAConnection, enlists the result of
XAConnection.getXAResource() with the current
transaction and returns the (wrapped) result of
XAConnection.getConnection() to the JPA implementation.

The JPA implementation is only supposed to register a Synchronization
instance during
EntityManagerFactory.createEntityManager() if a JTA transaction is active
at that time or during EntityManager.joinTransaction().

The JPA implementation is supposed to flush all changes, which have not
been flushed to the database yet in
Synchronization.beforeCompletion().

For this to work properly, a few conditions must be met:

case A: the JPA implementation has acquired and pinned a JDBC connection,
the associated XAResource is enlisted

condition A1. the container must not have delisted the resource when the
control flow leaves the container and the container is
about to commit (or rollback) the transaction. If the resource was delisted
before Transaction.commit(), the JDBC connection
is not currently associated to the JTA transaction and everything flushed
in beforeCompletion() is not part of the global
transaction.

condition A2. it must be supported to call Transaction.commit() while there
are still XAResources "active", i.e. start has been called,
while end has not been called, those should implicitly be "end()ed", before
the prepare and commit calls occurr.

condition A3. Transaction.commit() must execute the following in this
order:
-fire beforeCompletion
-implicit ending of XAResources, that have not been ended yet
-do all the prepare calls
-do all the commit calls

I assume, that most implementations of containers and transaction managers
already meet these conditions, either
by chance, by trial-and-error or by common-sense requirement extrapolation.
However I have not found out yet, that
any of these conditions is mandated by any of the related specs, and this
would be needed, otherwise the JPA-JTA interaction
relies on undefined behavior.

case B: the JPA implementation does not currently have a pinned JDBC
connection, when the container calls Transaction.commit()

condition B1: enlisting resources must be allowed if triggered from a
beforeCompletion() callback (because
the JPA implementation will acquire a connection right then)

condition B2: same as A2

condition B3: same as A3

I suggest, that these 4 conditions (B1 is debatable, JPA could be modified
to explicitly disallow that) should be addressed
in the upcoming JTA specification and in particular, an example
control-flow diagram like on p.28/29 of JTA 1.1 should be added

Thank you! (Sorry, that the mail became a bit long)

Regards,

Christian

Disclaimer: our own JPA implemention is not an ORM, but uses our
XA-capable, object-oriented database (Versant Object Database) directly,
so our implementation of the JTA-JPA might look slightly different because
of that, however I would like to see this problem
solved for the general ORM implementations of JPA as well


-- 
Christian Romberg
Chief Engineer | Versant GmbH
(T) +49 40 60990-0
(F) +49 40 60990-113
(E) cromberg_at_versant.com
www.versant.com<http://www.google.com/url?q=http%3A%2F%2Fwww.versant.com%2F&sa=D&sntz=1&usg=AFrqEzeeEBc_gN_8mxtt8xDB0tjXDXQVlw>|
www.db4o.com<http://www.google.com/url?q=http%3A%2F%2Fwww.db4o.com%2F&sa=D&sntz=1&usg=AFrqEzdo3Q40RwKQPBtnPIuBYQd1diFxJQ>
-- 
Versant
GmbH is incorporated in Germany. Company registration number: HRB
54723, Amtsgericht Hamburg. Registered Office: Halenreie 42, 22359
Hamburg, Germany. Geschäftsführer: Bernhard Wöbker, Volker John
CONFIDENTIALITY
NOTICE: This e-mail message, including any attachments, is for the sole
use of the intended recipient(s) and may contain confidential or
proprietary information. Any unauthorized review, use, disclosure or
distribution is prohibited. If you are not the intended recipient,
immediately contact the sender by reply e-mail and destroy all copies of
the original message.