📄 abstractplatformtransactionmanager.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.support;
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.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.UnexpectedRollbackException;
/**
* Abstract base class that allows for easy implementation of concrete
* platform transaction managers like JtaTransactionManager and
* HibernateTransactionManager.
*
* <p>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>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: 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 used for custom synchronization efforts.
*
* @author Juergen Hoeller
* @since 28.03.2003
* @version $Id: AbstractPlatformTransactionManager.java,v 1.25 2004/03/26 16:33:12 jhoeller Exp $
* @see #setTransactionSynchronization
* @see TransactionSynchronizationManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.orm.hibernate.HibernateTransactionManager
*/
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager {
/**
* 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);
protected final Log logger = LogFactory.getLog(getClass());
private int transactionSynchronization = SYNCHRONIZATION_ALWAYS;
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 if a rollback should be performed on failure of the commit call.
* Typically not necessary and thus to be avoided as it can override the
* commit exception with a subsequent rollback exception. Default is false.
*/
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;
}
/**
* This implementation of getTransaction handles propagation behavior.
* Delegates to doGetTransaction, isExistingTransaction, doBegin.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
// cache to avoid repeated checks
boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
logger.debug("Using transaction object [" + transaction + "]");
}
if (definition == null) {
// use defaults
definition = new DefaultTransactionDefinition();
}
if (isExistingTransaction(transaction)) {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException("Transaction propagation 'never' but existing transaction found");
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);
return newTransactionStatus(null, false, newSynchronization,
definition.isReadOnly(), debugEnabled, suspendedResources);
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Creating new transaction, suspending current one");
}
Object suspendedResources = suspend(transaction);
doBegin(transaction, definition);
boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
return newTransactionStatus(transaction, true, newSynchronization,
definition.isReadOnly(), debugEnabled, suspendedResources);
}
else {
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
return newTransactionStatus(transaction, false, newSynchronization,
definition.isReadOnly(), debugEnabled, null);
}
}
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Creating new transaction");
}
doBegin(transaction, definition);
boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
return newTransactionStatus(transaction, true, newSynchronization,
definition.isReadOnly(), debugEnabled, null);
}
else {
// "empty" (-> no) transaction
boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);
return newTransactionStatus(null, false, newSynchronization,
definition.isReadOnly(), debugEnabled, null);
}
}
/**
* Create a new TransactionStatus for the given arguments,
* initializing transaction synchronization if appropriate.
*/
private TransactionStatus newTransactionStatus(Object transaction, boolean newTransaction,
boolean newSynchronization, boolean readOnly,
boolean debug, Object suspendedResources) {
boolean actualNewSynchronization = newSynchronization &&
!TransactionSynchronizationManager.isSynchronizationActive();
if (actualNewSynchronization) {
TransactionSynchronizationManager.initSynchronization();
}
return new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization,
readOnly, debug, suspendedResources);
}
/**
* Suspend the given transaction. Suspends transaction synchronization first,
* then delegates to the doSuspend template method.
* @param transaction the current transaction object
* @return an object that holds suspended resources
* @see #doSuspend
* @see #resume
*/
private Object suspend(Object transaction) throws TransactionException {
List suspendedSynchronizations = null;
Object holder = doSuspend(transaction);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
suspendedSynchronizations = TransactionSynchronizationManager.getSynchronizations();
for (Iterator it = suspendedSynchronizations.iterator(); it.hasNext();) {
((TransactionSynchronization) it.next()).suspend();
}
TransactionSynchronizationManager.clearSynchronization();
}
return new SuspendedResourcesHolder(suspendedSynchronizations, holder);
}
/**
* Resume the given transaction. Delegates to the doResume template method
* first, then resuming transaction synchronization.
* @param transaction the current transaction object
* @param suspendedResources the object that holds suspended resources,
* as returned by suspend
* @see #doResume
* @see #suspend
*/
private void resume(Object transaction, Object suspendedResources) throws TransactionException {
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
if (resourcesHolder.getSuspendedSynchronizations() != null) {
TransactionSynchronizationManager.initSynchronization();
for (Iterator it = resourcesHolder.getSuspendedSynchronizations().iterator(); it.hasNext();) {
TransactionSynchronization synchronization = (TransactionSynchronization) it.next();
synchronization.resume();
TransactionSynchronizationManager.registerSynchronization(synchronization);
}
}
doResume(transaction, resourcesHolder.getSuspendedResources());
}
/**
* This implementation of commit handles participating in existing
* transactions and programmatic rollback requests.
* Delegates to isRollbackOnly, doCommit and rollback.
* @see org.springframework.transaction.TransactionStatus#isRollbackOnly
* @see #isRollbackOnly
* @see #doCommit
* @see #rollback
*/
public final void commit(TransactionStatus status) throws TransactionException {
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (status.isRollbackOnly() ||
(defStatus.getTransaction() != null && isRollbackOnly(defStatus.getTransaction()))) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
rollback(status);
}
else {
try {
boolean beforeCompletionInvoked = false;
try {
triggerBeforeCommit(defStatus);
triggerBeforeCompletion(defStatus, null);
beforeCompletionInvoked = true;
if (status.isNewTransaction()) {
logger.info("Initiating transaction commit");
doCommit(defStatus);
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
triggerAfterCompletion(defStatus, TransactionSynchronization.STATUS_ROLLED_BACK, ex);
throw ex;
}
catch (TransactionException ex) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -