📄 abstractplatformtransactionmanager.java
字号:
catch (Error err) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, err);
throw err;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
finally {
cleanupAfterCompletion(status);
}
}
/**
* This implementation of rollback handles participating in existing
* transactions. Delegates to <code>doRollback</code> and
* <code>doSetRollbackOnly</code>.
* @see #doRollback
* @see #doSetRollbackOnly
*/
public final void rollback(TransactionStatus status) throws TransactionException {
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
processRollback(defStatus);
}
/**
* Process an actual rollback.
* The completed flag has already been checked.
* @param status object representing the transaction
* @throws TransactionException in case of rollback failure
*/
private void processRollback(DefaultTransactionStatus status) {
try {
try {
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
else if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug(
"Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug(
"Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.warn("Should roll back transaction but cannot - no transaction available");
}
}
catch (RuntimeException ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
catch (Error err) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw err;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
finally {
cleanupAfterCompletion(status);
}
}
/**
* Invoke <code>doRollback</code>, handling rollback exceptions properly.
* @param status object representing the transaction
* @param ex the thrown application exception or error
* @throws TransactionException in case of rollback failure
* @see #doRollback
*/
private void doRollbackOnCommitException(DefaultTransactionStatus status, Throwable ex)
throws TransactionException {
try {
if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback on commit exception", ex);
}
doRollback(status);
}
}
catch (RuntimeException rbex) {
logger.error("Commit exception overridden by rollback exception", ex);
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw rbex;
}
catch (Error rberr) {
logger.error("Commit exception overridden by rollback exception", ex);
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw rberr;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
/**
* Trigger beforeCommit callbacks.
* @param status object representing the transaction
*/
private void triggerBeforeCommit(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
if (status.isDebug()) {
logger.debug("Triggering beforeCommit synchronization");
}
for (Iterator it = TransactionSynchronizationManager.getSynchronizations().iterator(); it.hasNext();) {
TransactionSynchronization synchronization = (TransactionSynchronization) it.next();
synchronization.beforeCommit(status.isReadOnly());
}
}
}
/**
* Trigger beforeCompletion callbacks.
* @param status object representing the transaction
*/
private void triggerBeforeCompletion(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
if (status.isDebug()) {
logger.debug("Triggering beforeCompletion synchronization");
}
for (Iterator it = TransactionSynchronizationManager.getSynchronizations().iterator(); it.hasNext();) {
TransactionSynchronization synchronization = (TransactionSynchronization) it.next();
try {
synchronization.beforeCompletion();
}
catch (Throwable tsex) {
logger.error("TransactionSynchronization.beforeCompletion threw exception", tsex);
}
}
}
}
/**
* Trigger afterCompletion callbacks.
* @param status object representing the transaction
* @param completionStatus completion status according to TransactionSynchronization constants
*/
private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) {
if (status.isNewSynchronization()) {
List synchronizations = TransactionSynchronizationManager.getSynchronizations();
if (!status.hasTransaction() || status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Triggering afterCompletion synchronization");
}
// No transaction or new transaction for the current scope ->
// invoke the afterCompletion callbacks immediately
invokeAfterCompletion(synchronizations, completionStatus);
}
else {
// Existing transaction that we participate in, controlled outside
// of the scope of this Spring transaction manager -> try to register
// an afterCompletion callback with the existing (JTA) transaction.
registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations);
}
}
}
/**
* Actually invoke the <code>afterCompletion</code> methods of the
* given Spring TransactionSynchronization objects.
* <p>To be called by this abstract manager itself, or by special implementations
* of the <code>registerAfterCompletionWithExistingTransaction</code> callback.
* @param synchronizations List of TransactionSynchronization objects
* @param completionStatus the completion status according to the
* constants in the TransactionSynchronization interface
* @see #registerAfterCompletionWithExistingTransaction(Object, java.util.List)
* @see TransactionSynchronization#STATUS_COMMITTED
* @see TransactionSynchronization#STATUS_ROLLED_BACK
* @see TransactionSynchronization#STATUS_UNKNOWN
*/
protected final void invokeAfterCompletion(List synchronizations, int completionStatus) {
for (Iterator it = synchronizations.iterator(); it.hasNext();) {
TransactionSynchronization synchronization = (TransactionSynchronization) it.next();
try {
synchronization.afterCompletion(completionStatus);
}
catch (Throwable tsex) {
logger.error("TransactionSynchronization.afterCompletion threw exception", tsex);
}
}
}
/**
* Clean up after completion, clearing synchronization if necessary,
* and invoking doCleanupAfterCompletion.
* @param status object representing the transaction
* @see #doCleanupAfterCompletion
*/
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clearSynchronization();
TransactionSynchronizationManager.setCurrentTransactionName(null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
if (status.isNewTransaction()) {
TransactionSynchronizationManager.setActualTransactionActive(false);
}
}
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());
}
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction");
}
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
//---------------------------------------------------------------------
// Template methods to be implemented in subclasses
//---------------------------------------------------------------------
/**
* Return a transaction object for the current transaction state.
* <p>The returned object will usually be specific to the concrete transaction
* manager implementation, carrying corresponding transaction state in a
* modifiable fashion. This object will be passed into the other template
* methods (e.g. doBegin and doCommit), either directly or as part of a
* DefaultTransactionStatus instance.
* <p>The returned object should contain information about any existing
* transaction, that is, a transaction that has already started before the
* current <code>getTransaction</code> call on the transaction manager.
* Consequently, a <code>doGetTransaction</code> implementation will usually
* look for an existing transaction and store corresponding state in the
* returned transaction object.
* @return the current transaction object
* @throws org.springframework.transaction.CannotCreateTransactionException
* if transaction support is not available
* @throws TransactionException in case of lookup or system errors
* @see #doBegin
* @see #doCommit
* @see #doRollback
* @see DefaultTransactionStatus#getTransaction
*/
protected abstract Object doGetTransaction() throws TransactionException;
/**
* Check if the given transaction object indicates an existing transaction
* (that is, a transaction which has already started).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -