📄 abstractplatformtransactionmanager.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.support;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.Constants;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidTimeoutException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.TransactionSuspensionNotSupportedException;
import org.springframework.transaction.UnexpectedRollbackException;
/**
* Abstract base class that allows for easy implementation of concrete
* platform transaction managers like JtaTransactionManager and
* DataSourceTransactionManager.
*
* <p>This base class provides the following workflow handling:
* <ul>
* <li>determines if there is an existing transaction;
* <li>applies the appropriate propagation behavior;
* <li>suspends and resumes transactions if necessary;
* <li>checks the rollback-only flag on commit;
* <li>applies the appropriate modification on rollback
* (actual rollback or setting rollback-only);
* <li>triggers registered synchronization callbacks
* (if transaction synchronization is active).
* </ul>
*
* <p>Subclasses have to implement specific template methods for specific
* states of a transaction, for example begin, suspend, resume, commit, rollback.
* The most important of them are abstract and must be provided by a concrete
* implementation; for the rest, defaults are provided, so overriding is optional.
*
* <p>Transaction synchronization is a generic mechanism for registering callbacks
* that get invoked at transaction completion time. This is mainly used internally
* by the data access support classes for JDBC, Hibernate, and JDO when running
* within a JTA transaction: They register resources that are opened within the
* transaction for closing at transaction completion time, allowing e.g. for reuse
* of the same Hibernate Session within the transaction. The same mechanism can
* also be leveraged for custom synchronization needs in an application.
*
* <p>The state of this class is serializable, to allow for serializing the
* transaction strategy along with proxies that carry a transaction interceptor.
* It is up to subclasses if they wish to make their state to be serializable too.
* They should implement the <code>java.io.Serializable</code> marker interface in
* that case, and potentially a private <code>readObject()</code> method (according
* to Java serialization rules) if they need to restore any transient state.
*
* @author Juergen Hoeller
* @since 28.03.2003
* @see #setTransactionSynchronization
* @see TransactionSynchronizationManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
* @see org.springframework.orm.hibernate.HibernateTransactionManager
* @see org.springframework.orm.jdo.JdoTransactionManager
*/
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
/**
* Always activate transaction synchronization, even for "empty" transactions
* that result from PROPAGATION_SUPPORTS with no existing backend transaction.
*/
public static final int SYNCHRONIZATION_ALWAYS = 0;
/**
* Activate transaction synchronization only for actual transactions,
* i.e. not for empty ones that result from PROPAGATION_SUPPORTS with no
* existing backend transaction.
*/
public static final int SYNCHRONIZATION_ON_ACTUAL_TRANSACTION = 1;
/**
* Never active transaction synchronization.
*/
public static final int SYNCHRONIZATION_NEVER = 2;
/** Constants instance for AbstractPlatformTransactionManager */
private static final Constants constants = new Constants(AbstractPlatformTransactionManager.class);
/** Transient to optimize serialization */
protected transient Log logger = LogFactory.getLog(getClass());
private int transactionSynchronization = SYNCHRONIZATION_ALWAYS;
private boolean nestedTransactionAllowed = false;
private boolean globalRollbackOnParticipationFailure = true;
private boolean rollbackOnCommitFailure = false;
/**
* Set the transaction synchronization by the name of the corresponding constant
* in this class, e.g. "SYNCHRONIZATION_ALWAYS".
* @param constantName name of the constant
* @see #SYNCHRONIZATION_ALWAYS
*/
public void setTransactionSynchronizationName(String constantName) {
setTransactionSynchronization(constants.asNumber(constantName).intValue());
}
/**
* Set when this transaction manager should activate the thread-bound
* transaction synchronization support. Default is "always".
* <p>Note that transaction synchronization isn't supported for
* multiple concurrent transactions by different transaction managers.
* Only one transaction manager is allowed to activate it at any time.
* @see #SYNCHRONIZATION_ALWAYS
* @see #SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
* @see #SYNCHRONIZATION_NEVER
* @see TransactionSynchronizationManager
* @see TransactionSynchronization
*/
public void setTransactionSynchronization(int transactionSynchronization) {
this.transactionSynchronization = transactionSynchronization;
}
/**
* Return if this transaction manager should activate the thread-bound
* transaction synchronization support.
*/
public int getTransactionSynchronization() {
return transactionSynchronization;
}
/**
* Set whether nested transactions are allowed. Default is "false".
* <p>Typically initialized with an appropriate default by the
* concrete transaction manager subclass.
*/
public void setNestedTransactionAllowed(boolean nestedTransactionAllowed) {
this.nestedTransactionAllowed = nestedTransactionAllowed;
}
/**
* Return whether nested transactions are allowed.
*/
public boolean isNestedTransactionAllowed() {
return nestedTransactionAllowed;
}
/**
* Set whether to globally mark an existing transaction as rollback-only
* after a participating transaction failed.
* <p>Default is "true": If a participating transaction (e.g. with
* PROPAGATION_REQUIRES or PROPAGATION_SUPPORTS encountering an existing
* transaction) fails, the transaction will be globally marked as rollback-only.
* The only possible outcome of such a transaction is a rollback: The
* transaction originator <i>cannot</i> make the transaction commit anymore.
* <p>Switch this to "false" to let the transaction originator make the rollback
* decision. If a participating transaction fails with an exception, the caller
* can still decide to continue with a different path within the transaction.
* However, note that this will only work as long as all participating resources
* are capable of contiuing towards a transaction commit even after a data access
* failure: This is generally not the case for a Hibernate Session, for example;
* neither is it for a sequence of JDBC insert/update/delete operations.
* <p><b>Note:</b>This flag only applies to an explicit rollback attempt for a
* subtransaction, typically caused by an exception thrown by a data access operation
* (where TransactionInterceptor will trigger a <code>PlatformTransactionManager.rollback()</code>
* call according to a rollback rule). If the flag is off, the caller can handle the exception
* and decide on a rollback, independent of the rollback rules of the subtransaction.
* This flag does, however, <i>not</i> apply to explicit <code>setRollbackOnly</code>
* calls on a <code>TransactionStatus</code>, which will always cause an eventual
* global rollback (as it might not throw an exception after the rollback-only call).
* <p>The recommended solution for handling failure of a subtransaction
* is a "nested transaction", where the global transaction can be rolled
* back to a savepoint taken at the beginning of the subtransaction.
* PROPAGATION_NESTED provides exactly those semantics; however, it will
* only work when nested transaction support is available. This is the case
* with DataSourceTransactionManager, but not with JtaTransactionManager.
* @see #setNestedTransactionAllowed
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
public void setGlobalRollbackOnParticipationFailure(boolean globalRollbackOnParticipationFailure) {
this.globalRollbackOnParticipationFailure = globalRollbackOnParticipationFailure;
}
/**
* Return whether to globally mark an existing transaction as rollback-only
* after a participating transaction failed.
*/
public boolean isGlobalRollbackOnParticipationFailure() {
return globalRollbackOnParticipationFailure;
}
/**
* Set if doRollback should be performed on failure of the doCommit call.
* Typically not necessary and thus to be avoided as it can override the
* commit exception with a subsequent rollback exception. Default is "false".
* @see #doCommit
* @see #doRollback
*/
public void setRollbackOnCommitFailure(boolean rollbackOnCommitFailure) {
this.rollbackOnCommitFailure = rollbackOnCommitFailure;
}
/**
* Return if a rollback should be performed on failure of the commit call.
*/
public boolean isRollbackOnCommitFailure() {
return rollbackOnCommitFailure;
}
//---------------------------------------------------------------------
// Implementation of PlatformTransactionManager
//---------------------------------------------------------------------
/**
* This implementation handles propagation behavior. Delegates to
* <code>doGetTransaction</code>, <code>isExistingTransaction</code>
* and <code>doBegin</code>.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
logger.debug("Using transaction object [" + transaction + "]");
}
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -