This transaction manager is appropriate for applications that use a single
JDO PersistenceManagerFactory for transactional data access. JTA (usually through
JtaTransactionManager) is necessary
for accessing multiple transactional resources within the same transaction.
Note that you need to configure your JDO provider accordingly in order to make
it participate in JTA transactions.

Note: To be able to register a DataSource's Connection for plain JDBC code,
this instance needs to be aware of the DataSource (setDataSource(javax.sql.DataSource)).
The given DataSource should obviously match the one used by the given
PersistenceManagerFactory. This transaction manager will autodetect the DataSource
that acts as "connectionFactory" of the PersistenceManagerFactory, so you usually
don't need to explicitly specify the "dataSource" property.

On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0
Savepoints. The AbstractPlatformTransactionManager.setNestedTransactionAllowed(boolean) "nestedTransactionAllowed"}
flag defaults to "false", though, as nested transactions will just apply to the
JDBC Connection, not to the JDO PersistenceManager and its cached objects.
You can manually set the flag to "true" if you want to use nested transactions
for JDBC access code which participates in JDO transactions (provided that your
JDBC driver supports Savepoints). Note that JDO itself does not support
nested transactions! Hence, do not expect JDO access code to semantically
participate in a nested transaction.

Method Detail

setPersistenceManagerFactory

Set the PersistenceManagerFactory that this instance should manage transactions for.

The PersistenceManagerFactory specified here should be the target
PersistenceManagerFactory to manage transactions for, not a
TransactionAwarePersistenceManagerFactoryProxy. Only data access
code may work with TransactionAwarePersistenceManagerFactoryProxy, while the
transaction manager needs to work on the underlying target PersistenceManagerFactory.

getPersistenceManagerFactory

public javax.jdo.PersistenceManagerFactory getPersistenceManagerFactory()

Return the PersistenceManagerFactory that this instance should manage transactions for.

setDataSource

public void setDataSource(javax.sql.DataSource dataSource)

Set the JDBC DataSource that this instance should manage transactions for.
The DataSource should match the one used by the JDO PersistenceManagerFactory:
for example, you could specify the same JNDI DataSource for both.

If the PersistenceManagerFactory uses a DataSource as connection factory,
the DataSource will be autodetected: You can still explictly specify the
DataSource, but you don't need to in this case.

A transactional JDBC Connection for this DataSource will be provided to
application code accessing this DataSource directly via DataSourceUtils
or JdbcTemplate. The Connection will be taken from the JDO PersistenceManager.

Note that you need to use a JDO dialect for a specific JDO provider to
allow for exposing JDO transactions as JDBC transactions.

The DataSource specified here should be the target DataSource to manage
transactions for, not a TransactionAwareDataSourceProxy. Only data access
code may work with TransactionAwareDataSourceProxy, while the transaction
manager needs to work on the underlying target DataSource. If there's
nevertheless a TransactionAwareDataSourceProxy passed in, it will be
unwrapped to extract its target DataSource.

doGetTransaction

The returned object will usually be specific to the concrete transaction
manager implementation, carrying corresponding transaction state in a
modifiable fashion. This object will be passed into the other template
methods (e.g. doBegin and doCommit), either directly or as part of a
DefaultTransactionStatus instance.

The returned object should contain information about any existing
transaction, that is, a transaction that has already started before the
current getTransaction call on the transaction manager.
Consequently, a doGetTransaction implementation will usually
look for an existing transaction and store corresponding state in the
returned transaction object.

isExistingTransaction

Check if the given transaction object indicates an existing transaction
(that is, a transaction which has already started).

The result will be evaluated according to the specified propagation
behavior for the new transaction. An existing transaction might get
suspended (in case of PROPAGATION_REQUIRES_NEW), or the new transaction
might participate in the existing one (in case of PROPAGATION_REQUIRED).

The default implementation returns false, assuming that
participating in existing transactions is generally not supported.
Subclasses are of course encouraged to provide such support.

doBegin

Begin a new transaction with semantics according to the given transaction
definition. Does not have to care about applying the propagation behavior,
as this has already been handled by this abstract manager.

This method gets called when the transaction manager has decided to actually
start a new transaction. Either there wasn't any transaction before, or the
previous transaction has been suspended.

A special scenario is a nested transaction without savepoint: If
useSavepointForNestedTransaction() returns "false", this method
will be called to start a nested transaction when necessary. In such a context,
there will be an active transaction: The implementation of this method has
to detect this and start an appropriate nested transaction.

doCommit

An implementation does not need to check the "new transaction" flag
or the rollback-only flag; this will already have been handled before.
Usually, a straight commit will be performed on the transaction object
contained in the passed-in status.

doRollback

An implementation does not need to check the "new transaction" flag;
this will already have been handled before. Usually, a straight rollback
will be performed on the transaction object contained in the passed-in status.

doSetRollbackOnly

Set the given transaction rollback-only. Only called on rollback
if the current transaction participates in an existing one.

The default implementation throws an IllegalTransactionStateException,
assuming that participating in existing transactions is generally not
supported. Subclasses are of course encouraged to provide such support.