📄 jtatransactionmanager.java
字号:
/*
* Copyright 2002-2006 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 java.util.List;
import java.util.Properties;
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.Synchronization;
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;
import org.springframework.transaction.support.TransactionSynchronization;
/**
* 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 well-defined JTA object is
* <i>not</i> specified by J2EE; it is specific to each J2EE server, often kept
* in JNDI like the JTA UserTransaction. Some well-known JNDI locations are:
* <ul>
* <li>"java:comp/UserTransaction" for Resin 2.x, Oracle OC4J (Orion),
* JOnAS (JOTM), BEA WebLogic
* <li>"java:comp/TransactionManager" for Resin 3.x
* <li>"java:pm/TransactionManager" for Borland Enterprise Server and
* Sun Application Server (Sun ONE 7 and later)
* <li>"java:/TransactionManager" for JBoss Application Server
* </ul>
*
* <p>All of these cases are autodetected by JtaTransactionManager (since Spring 1.2),
* provided that the "autodetectTransactionManager" flag is set to "true" (which it is
* by default). Consequently, JtaTransactionManager will support transaction suspension
* out-of-the-box on many J2EE servers.
*
* <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 <code>null</code>,
* to suppress the default "java:comp/UserTransaction" JNDI lookup and thus enforce
* use of the given JTA TransactionManager even for begin, commit and rollback.
*
* <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><b>This standard JtaTransactionManager supports timeouts but not per-transaction
* isolation levels.</b> Custom subclasses can override <code>doJtaBegin</code> for
* specific JTA implementations to provide this functionality; Spring includes a
* corresponding WebLogicJtaTransactionManager class, for example. Such adapters
* for specific J2EE transaction coordinators can also expose transaction names
* for monitoring; with standard JTA, transaction names will be ignored.
*
* <p><b>Consider using WebLogicJtaTransactionManager on BEA WebLogic, which supports
* the full power of Spring's transaction definitions on WebLogic's transaction
* coordinator</b>, <i>beyond standard JTA</i>: transaction names, per-transaction
* isolation levels, and proper resuming of transactions in all cases.
* WebLogicJtaTransactionManager automatically adapts to WebLogic 7.0 or 8.1+.
*
* <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 #doJtaBegin
* @see JotmFactoryBean
* @see WebSphereTransactionManagerFactoryBean
* @see WebLogicJtaTransactionManager
* @see org.springframework.jndi.JndiObjectFactoryBean
* @see org.springframework.orm.hibernate.LocalSessionFactoryBean#setJtaTransactionManager
*/
public class JtaTransactionManager extends AbstractPlatformTransactionManager
implements InitializingBean, Serializable {
/**
* Default JNDI location for the JTA UserTransaction. Many J2EE servers
* also provide support for the JTA TransactionManager interface there.
* @see #setUserTransactionName
* @see #setAutodetectTransactionManager
*/
public static final String DEFAULT_USER_TRANSACTION_NAME = "java:comp/UserTransaction";
/**
* Fallback JNDI locations for the JTA TransactionManager. Applied if
* the JTA UserTransaction does not implement the JTA TransactionManager
* interface, provided that the "autodetectTransactionManager" flag is "true".
* @see #setTransactionManagerName
* @see #setAutodetectTransactionManager
*/
public static final String[] FALLBACK_TRANSACTION_MANAGER_NAMES =
new String[] {"java:comp/TransactionManager", "java:pm/TransactionManager", "java:/TransactionManager"};
private transient JndiTemplate jndiTemplate = new JndiTemplate();
private transient UserTransaction userTransaction;
private String userTransactionName = DEFAULT_USER_TRANSACTION_NAME;
private boolean cacheUserTransaction = true;
private transient TransactionManager transactionManager;
private String transactionManagerName;
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();
// Do not attempt UserTransaction lookup: use given TransactionManager
// to get a UserTransaction handle.
this.userTransactionName = null;
this.transactionManager = transactionManager;
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 environment to use for JNDI lookups.
* Creates a JndiTemplate with the given environment settings.
* @see #setJndiTemplate
*/
public void setJndiEnvironment(Properties jndiEnvironment) {
this.jndiTemplate = new JndiTemplate(jndiEnvironment);
}
/**
* Return the JNDI environment to use for JNDI lookups.
*/
public Properties getJndiEnvironment() {
return this.jndiTemplate.getEnvironment();
}
/**
* 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;
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -