jtatransactionmanager.java

来自「spring framework 2.5.4源代码」· Java 代码 · 共 1,215 行 · 第 1/4 页

JAVA
1,215
字号
/*
 * Copyright 2002-2008 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.TransactionSynchronizationRegistry;
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.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;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * {@link org.springframework.transaction.PlatformTransactionManager} implementation
 * for JTA, delegating to a backend JTA provider. This is typically used to delegate
 * to a J2EE server's transaction coordinator, but may also be configured with a
 * local JTA provider which is embedded within the application.
 *
 * <p>This transaction manager is appropriate for handling distributed transactions,
 * i.e. transactions that span multiple resources, and for controlling transactions on
 * application server resources (e.g. JDBC DataSources available in JNDI) in general.
 * For a single JDBC DataSource, DataSourceTransactionManager is perfectly sufficient,
 * and for accessing a single resource with Hibernate (including transactional cache),
 * HibernateTransactionManager is appropriate, for example.
 *
 * <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, JDO etc
 * 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><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:appserver/TransactionManager" for GlassFish
 * <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, provided that the
 * "autodetectTransactionManager" flag is set to "true" (which it is by default).
 *
 * <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>
 * As a consequence, Spring provides various vendor-specific PlatformTransactionManagers,
 * which are recommended to be used if appropriate: {@link WebLogicJtaTransactionManager},
 * {@link WebSphereUowTransactionManager} and {@link OC4JJtaTransactionManager}.
 * For all other J2EE servers, the standard JtaTransactionManager is sufficient.
 *
 * <p><b>Consider using Spring 2.5's <code>tx:jta-transaction-manager</code> configuration
 * element for automatically picking the appropriate JTA platform transaction manager
 * (automatically detecting WebLogic, WebSphere and OC4J).</b>
 *
 * <p><b>This pure JtaTransactionManager supports timeouts but not per-transaction
 * isolation levels.</b> Custom subclasses may override {@link #doJtaBegin} for
 * specific JTA extensions in order to provide this functionality; Spring includes
 * corresponding {@link WebLogicJtaTransactionManager} and {@link OC4JJtaTransactionManager}
 * classes, for BEA's WebLogic Server and Oracle's OC4J, respectively. Such adapters
 * for specific J2EE transaction coordinators may also expose transaction names for
 * monitoring; with standard JTA, transaction names will simply be ignored.
 *
 * <p>JTA 1.1 adds the TransactionSynchronizationRegistry facility, as public Java EE 5
 * API in addition to the standard JTA UserTransaction handle. As of Spring 2.5, this
 * JtaTransactionManager autodetects the TransactionSynchronizationRegistry and uses
 * it for registering Spring-managed synchronizations when participating in an existing
 * JTA transaction (e.g. controlled by EJB CMT). If no TransactionSynchronizationRegistry
 * is available (or the JTA 1.1 API isn't available), then such synchronizations
 * will be registered via the (non-J2EE) JTA TransactionManager handle.
 *
 * <p>This class is serializable. However, active synchronizations do not survive
 * serialization.
 *
 * @author Juergen Hoeller
 * @since 24.03.2003
 * @see javax.transaction.UserTransaction
 * @see javax.transaction.TransactionManager
 * @see javax.transaction.TransactionSynchronizationRegistry
 * @see #setUserTransactionName
 * @see #setUserTransaction
 * @see #setTransactionManagerName
 * @see #setTransactionManager
 * @see JotmFactoryBean
 * @see WebSphereTransactionManagerFactoryBean
 * @see WebLogicJtaTransactionManager
 */
public class JtaTransactionManager extends AbstractPlatformTransactionManager
		implements TransactionFactory, 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:appserver/TransactionManager",
					"java:pm/TransactionManager", "java:/TransactionManager"};

	/**
	 * Standard Java EE 5 JNDI location for the JTA TransactionSynchronizationRegistry.
	 * Autodetected when available.
	 */
	public static final String DEFAULT_TRANSACTION_SYNCHRONIZATION_REGISTRY_NAME =
			"java:comp/TransactionSynchronizationRegistry";


	private static final String TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME =
			"javax.transaction.TransactionSynchronizationRegistry";


	private transient JndiTemplate jndiTemplate = new JndiTemplate();

	private transient UserTransaction userTransaction;

	private String userTransactionName;

	private boolean autodetectUserTransaction = true;

	private boolean cacheUserTransaction = true;

	private boolean userTransactionObtainedFromJndi = false;

	private transient TransactionManager transactionManager;

	private String transactionManagerName;

	private boolean autodetectTransactionManager = true;

	private String transactionSynchronizationRegistryName;

	private transient Object transactionSynchronizationRegistry;

	private boolean allowCustomIsolationLevels = false;


	/**
	 * Create a new JtaTransactionManager instance, to be configured as bean.
	 * Invoke <code>afterPropertiesSet</code> 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();
		Assert.notNull(userTransaction, "UserTransaction must not be null");
		this.userTransaction = userTransaction;
	}

	/**
	 * 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();
		Assert.notNull(userTransaction, "UserTransaction must not be null");
		Assert.notNull(transactionManager, "TransactionManager must not be null");
		this.userTransaction = userTransaction;
		this.transactionManager = transactionManager;
	}

	/**
	 * Create a new JtaTransactionManager instance.
	 * @param transactionManager the JTA TransactionManager to use as direct reference
	 */
	public JtaTransactionManager(TransactionManager transactionManager) {
		this();
		Assert.notNull(transactionManager, "TransactionManager must not be null");
		this.transactionManager = transactionManager;
		this.userTransaction = buildUserTransaction(transactionManager);
	}


	/**
	 * 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 this.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.
	 * <p>Typically just used for local JTA setups; in a J2EE environment,
	 * the UserTransaction will always be fetched from JNDI.
	 * @see #setUserTransactionName
	 * @see #setAutodetectUserTransaction
	 */
	public void setUserTransaction(UserTransaction userTransaction) {
		this.userTransaction = userTransaction;
	}

	/**
	 * Return the JTA UserTransaction that this transaction manager uses.
	 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?