📄 jtatransactionmanager.java
字号:
/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction.jta;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import javax.naming.NamingException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jndi.JndiTemplate;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.HeuristicCompletionException;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidIsolationLevelException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionSuspensionNotSupportedException;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.UnexpectedRollbackException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
/**
* PlatformTransactionManager implementation for JTA, i.e. J2EE container transactions.
* Can also work with a locally configured JTA implementation.
*
* <p>This transaction manager is appropriate for handling distributed transactions,
* i.e. transactions that span multiple resources, and for managing transactions
* on a J2EE Connector (e.g. a persistence toolkit registered as JCA Connector).
* For a single JDBC DataSource, DataSourceTransactionManager is perfectly sufficient,
* and for accessing a single resource with Hibernate (including transactional cache),
* HibernateTransactionManager is appropriate.
*
* <p>Transaction synchronization is active by default, to allow data access support
* classes to register resources that are opened within the transaction for closing at
* transaction completion time. Spring's support classes for JDBC, Hibernate and JDO
* all perform such registration, allowing for reuse of the same Hibernate Session etc
* within the transaction. Standard JTA does not even guarantee that for Connections
* from a transactional JDBC DataSource: Spring's synchronization solves those issues.
*
* <p>Synchronization is also leveraged for transactional cache handling with Hibernate.
* Therefore, as long as JtaTransactionManager drives the JTA transactions, there is
* no need to configure Hibernate's JTATransaction strategy or a container-specific
* Hibernate TransactionManagerLookup. However, certain JTA implementations are
* restrictive in terms of what JDBC calls they allow after transaction completion,
* complaining even on close calls: In that case, it is indeed necessary to configure a
* Hibernate TransactionManagerLookup, potentially via Spring's LocalSessionFactoryBean.
*
* <p>If JtaTransactionManager participates in an existing JTA transaction, e.g. from
* EJB CMT, synchronization will be triggered on finishing the nested transaction,
* before passing transaction control back to the J2EE container. In this case, a
* container-specific Hibernate TransactionManagerLookup is the only way to achieve
* exact afterCompletion callbacks for transactional cache handling with Hibernate.
*
* <p><b>For typical JTA transactions (REQUIRED, SUPPORTS, MANDATORY, NEVER), a plain
* JtaTransactionManager definition is all you need, completely portable across all
* J2EE servers.</b> This corresponds to the functionality of the JTA UserTransaction,
* for which J2EE specifies a standard JNDI name ("java:comp/UserTransaction").
* There is no need to configure a server-specific TransactionManager lookup for this
* kind of JTA usage.
*
* <p><b>Note: Advanced JTA usage below. Dealing with these mechanisms is not
* necessary for typical usage scenarios.</b>
*
* <p>Transaction suspension (REQUIRES_NEW, NOT_SUPPORTED) is just available with
* a JTA TransactionManager being registered, via the "transactionManagerName" or
* "transactionManager" property. The location of this internal JTA object is
* <i>not</i> specified by J2EE; it is individual for each J2EE server, often kept
* in JNDI like the UserTransaction. Some well-known JNDI locations are:
* <ul>
* <li>"java:comp/UserTransaction" for Resin, Orion (Oracle OC4J), JOnAS (JOTM),
* BEA WebLogic (unofficial)
* <li>"javax.transaction.TransactionManager" for BEA WebLogic (official)
* <li>"java:/TransactionManager" for JBoss, JRun4
* </ul>
*
* <p>"java:comp/UserTransaction" as JNDI name for the TransactionManager means that
* the same JTA object implements both the UserTransaction and the TransactionManager
* interface. As this is easy to test when looking up the UserTransaction, this will
* be autodetected on initialization of JtaTransactionManager. In this case, there's
* no need to specify the "transactionManagerName" (for Resin, Orion, JOnAS, WebLogic).
*
* <p>A JNDI lookup can also be factored out into a corresponding JndiObjectFactoryBean,
* passed into JtaTransactionManager's "transactionManager" property. Such a bean
* definition can then be reused by other objects, for example Spring's
* LocalSessionFactoryBean for Hibernate (see below).
*
* <p>For IBM WebSphere and standalone JOTM, static accessor methods are required to
* obtain the JTA TransactionManager: Therefore, WebSphere and JOTM have their own
* FactoryBean implementations, to be wired with the "transactionManager" property.
* In case of JotmFactoryBean, the same JTA object implements UserTransaction too:
* Therefore, passing the object to the "userTransaction" property is sufficient.
*
* <p>It is also possible to specify a JTA TransactionManager only, either through
* the corresponding constructor or through the "transactionManager" property.
* In the latter case, the "userTransactionName" property needs to be set to null,
* to avoid a "java:comp/UserTransaction" JNDI lookup and thus enforcing to build
* a UserTransaction handle for the given JTA TransactionManager.
*
* <p><b>Note: Support for the JTA TransactionManager interface is not required by J2EE.
* Almost all J2EE servers expose it, but do so as extension to J2EE. There might be some
* issues with compatibility, despite the TransactionManager interface being part of JTA.</b>
* The only currently known problem is resuming a transaction on WebLogic, which by default
* fails if the suspended transaction was marked rollback-only; for other usages, it works
* properly. Use Spring's WebLogicJtaTransactionManager to enforce a resume in any case.
*
* <p>The JTA TransactionManager can also be used to register custom synchronizations
* with the JTA transaction itself instead of Spring's transaction manager. This is
* particularly useful for closing resources with strict JTA implementations such as
* Weblogic's or WebSphere's that do not allow any access to resources after transaction
* completion, not even for cleanup. For example, Hibernate access is affected by this
* issue, as outlined above in the discussion of transaction synchronization.
*
* <p>Spring's LocalSessionFactoryBean for Hibernate supports plugging a given
* JTA TransactionManager into Hibernate's TransactionManagerLookup mechanism,
* for Hibernate-driven cache synchronization and proper cleanup without warnings.
* The same JTA TransactionManager configuration as above can be used in this case
* (with a JndiObjectFactoryBean for a JNDI lookup, or one of the FactoryBeans),
* avoiding double configuration. Alternatively, specify corresponding Hibernate
* properties (see Hibernate docs for details).
*
* <p>JtaTransactionManager supports timeouts but not custom isolation levels.
* Custom subclasses can override <code>applyIsolationLevel</code> for specific JTA
* implementations. Note that some resource-specific transaction managers like
* DataSourceTransactionManager and HibernateTransactionManager do support timeouts,
* custom isolation levels, and transaction suspension without JTA's restrictions.
*
* <p>This class is serializable. Active synchronizations do not survive
* serialization, though.
*
* @author Juergen Hoeller
* @since 24.03.2003
* @see #setUserTransactionName
* @see #setUserTransaction
* @see #setTransactionManagerName
* @see #setTransactionManager
* @see #applyIsolationLevel
* @see JotmFactoryBean
* @see WebSphereTransactionManagerFactoryBean
* @see WebLogicJtaTransactionManager
* @see org.springframework.jndi.JndiObjectFactoryBean
* @see org.springframework.orm.hibernate.LocalSessionFactoryBean#setJtaTransactionManager
* @see org.springframework.orm.hibernate.HibernateTransactionManager
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
public class JtaTransactionManager extends AbstractPlatformTransactionManager
implements InitializingBean, Serializable {
public static final String DEFAULT_USER_TRANSACTION_NAME = "java:comp/UserTransaction";
private transient JndiTemplate jndiTemplate = new JndiTemplate();
private String userTransactionName = DEFAULT_USER_TRANSACTION_NAME;
private transient UserTransaction userTransaction;
private String transactionManagerName;
private transient TransactionManager transactionManager;
private boolean autodetectTransactionManager = true;
/**
* Create a new JtaTransactionManager instance, to be configured as bean.
* Invoke afterPropertiesSet to activate the configuration.
* @see #setUserTransactionName
* @see #setUserTransaction
* @see #setTransactionManagerName
* @see #setTransactionManager
* @see #afterPropertiesSet
*/
public JtaTransactionManager() {
setNestedTransactionAllowed(true);
}
/**
* Create a new JtaTransactionManager instance.
* @param userTransaction the JTA UserTransaction to use as direct reference
*/
public JtaTransactionManager(UserTransaction userTransaction) {
this();
this.userTransaction = userTransaction;
afterPropertiesSet();
}
/**
* Create a new JtaTransactionManager instance.
* @param userTransaction the JTA UserTransaction to use as direct reference
* @param transactionManager the JTA TransactionManager to use as direct reference
*/
public JtaTransactionManager(UserTransaction userTransaction, TransactionManager transactionManager) {
this();
this.userTransaction = userTransaction;
this.transactionManager = transactionManager;
afterPropertiesSet();
}
/**
* Create a new JtaTransactionManager instance.
* @param transactionManager the JTA TransactionManager to use as direct reference
*/
public JtaTransactionManager(TransactionManager transactionManager) {
this();
this.transactionManager = transactionManager;
// Do not attempt UserTransaction lookup: use given TransactionManager
// to get a UserTransaction handle.
this.userTransactionName = null;
afterPropertiesSet();
}
/**
* Set the JndiTemplate to use for JNDI lookups.
* A default one is used if not set.
*/
public void setJndiTemplate(JndiTemplate jndiTemplate) {
if (jndiTemplate == null) {
throw new IllegalArgumentException("jndiTemplate must not be null");
}
this.jndiTemplate = jndiTemplate;
}
/**
* Return the JndiTemplate used for JNDI lookups.
*/
public JndiTemplate getJndiTemplate() {
return jndiTemplate;
}
/**
* Set the JNDI name of the JTA UserTransaction.
* The J2EE default "java:comp/UserTransaction" is used if not set.
* @see #DEFAULT_USER_TRANSACTION_NAME
* @see #setUserTransaction
*/
public void setUserTransactionName(String userTransactionName) {
this.userTransactionName = userTransactionName;
}
/**
* Set the JTA UserTransaction to use as direct reference.
* Typically just used for local JTA setups; in a J2EE environment,
* the UserTransaction will always be fetched from JNDI.
* @see #setUserTransactionName
*/
public void setUserTransaction(UserTransaction userTransaction) {
this.userTransaction = userTransaction;
}
/**
* Return the JTA UserTransaction that this transaction manager uses.
*/
public UserTransaction getUserTransaction() {
return userTransaction;
}
/**
* Set the JNDI name of the JTA TransactionManager.
* <p>A TransactionManager is necessary for suspending and resuming transactions,
* as this not supported by the UserTransaction interface.
* <p>Note that the TransactionManager will be autodetected if the JTA
* UserTransaction object implements the JTA TransactionManager interface too.
* @see #setTransactionManager
*/
public void setTransactionManagerName(String transactionManagerName) {
this.transactionManagerName = transactionManagerName;
}
/**
* Set the JTA TransactionManager to use as direct reference.
* <p>A TransactionManager is necessary for suspending and resuming transactions,
* as this not supported by the UserTransaction interface.
* <p>Note that the TransactionManager will be autodetected if the JTA
* UserTransaction object implements the JTA TransactionManager interface too.
* @see #setTransactionManagerName
* @see #setAutodetectTransactionManager
*/
public void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -