📄 abstractplatformtransactionmanager.java
字号:
TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus);
}
/**
* 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.clear();
}
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).
* <p>The result will be evaluated according to the specified propagation
* behavior for the new transaction. An existing transaction might get
* suspended (in case of PROPAGATION_REQUIRES_NEW), or the new transaction
* might participate in the existing one (in case of PROPAGATION_REQUIRED).
* <p>The default implementation returns <code>false</code>, assuming that
* participating in existing transactions is generally not supported.
* Subclasses are of course encouraged to provide such support.
* @param transaction transaction object returned by doGetTransaction
* @return if there is an existing transaction
* @throws TransactionException in case of system errors
* @see #doGetTransaction
*/
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
return false;
}
/**
* Return whether to use a savepoint for a nested transaction.
* <p>Default is <code>true</code>, which causes delegation to DefaultTransactionStatus
* for creating and holding a savepoint. If the transaction object does not implement
* the SavepointManager interface, a NestedTransactionNotSupportedException will be
* thrown. Else, the SavepointManager will be asked to create a new savepoint to
* demarcate the start of the nested transaction.
* <p>Subclasses can override this to return <code>false</code>, causing a further
* call to <code>doBegin</code> - within the context of an already existing transaction.
* The <code>doBegin</code> implementation needs to handle this accordingly in such
* a scenario. This is appropriate for JTA, for example.
* @see DefaultTransactionStatus#createAndHoldSavepoint
* @see DefaultTransactionStatus#rollbackToHeldSavepoint
* @see DefaultTransactionStatus#releaseHeldSavepoint
* @see #doBegin
*/
protected boolean useSavepointForNestedTransaction() {
return true;
}
/**
* Begin a new transaction with semantics according to the given transaction
* definition. Does not have to care about applying the propagation behavior,
* as this has already been handled by this abstract manager.
* <p>This method gets called when the transaction manager has decided to actually
* start a new transaction. Either there wasn't any transaction before, or the
* previous transaction has been suspended.
* <p>A special scenario is a nested transaction without savepoint: If
* <code>useSavepointForNestedTransaction()</code> returns "false", this method
* will be called to start a nested transaction when necessary. In such a context,
* there will be an active transaction: The implementation of this method has
* to detect this and start an appropriate nested transaction.
* @param transaction transaction object returned by <code>doGetTransaction</code>
* @param definition TransactionDefinition instance, describing propagation
* behavior, isolation level, read-only flag, timeout, and transaction name
* @throws TransactionException in case of creation or system errors
*/
protected abstract void doBegin(Object transaction, TransactionDefinition definition)
throws TransactionException;
/**
* Suspend the resources of the current transaction.
* Transaction synchronization will already have been suspended.
* <p>The default implementation throws a TransactionSuspensionNotSupportedException,
* assuming that transaction suspension is generally not supported.
* @param transaction transaction object returned by <code>doGetTransaction</code>
* @return an object that holds suspended resources
* (will be kept unexamined for passing it into doResume)
* @throws org.springframework.transaction.TransactionSuspensionNotSupportedException
* if suspending is not supported by the transaction manager implementation
* @throws TransactionException in case of system errors
* @see #doResume
*/
protected Object doSuspend(Object transaction) throws TransactionException {
throw new TransactionSuspensionNotSupportedException(
"Transaction manager [" + getClass().getName() + "] does not support transaction suspension");
}
/**
* Resume the resources of the current transaction.
* Transaction synchronization will be resumed afterwards.
* <p>The default implementation throws a TransactionSuspensionNotSupportedException,
* assuming that transaction suspension is generally not supported.
* @param transaction transaction object returned by <code>doGetTransaction</code>
* @param suspendedResources the object that holds suspended resources,
* as returned by doSuspend
* @throws org.springframework.transaction.TransactionSuspensionNotSupportedException
* if resuming is not supported by the transaction manager implementation
* @throws TransactionException in case of system errors
* @see #doSuspend
*/
protected void doResume(Object transaction, Object suspendedResources) throws TransactionException {
throw new TransactionSuspensionNotSupportedException(
"Transaction manager [" + getClass().getName() + "] does not support transaction suspension");
}
/**
* Return whether to call <code>doCommit</code> on a transaction that has been
* marked as rollback-only in a global fashion.
* <p>Does not apply if an application locally sets the transaction to rollback-only
* via the TransactionStatus, but only to the transaction itself being marked as
* rollback-only by the transaction coordinator.
* <p>Default is "false": Local transaction strategies usually don't hold the rollback-only
* marker in the transaction itself, therefore they can't handle rollback-only transactions
* as part of transaction commit. Hence, AbstractPlatformTransactionManager will trigger
* a rollback in that case, throwing an UnexpectedRollbackException afterwards.
* <p>Override this to return "true" if the concrete transaction manager expects a
* <code>doCommit</code> call even for a rollback-only transaction, allowing for
* special handling there. This will, for example, be the case for JTA, where
* <code>UserTransaction.commit</code> will check the read-only flag itself and
* throw a corresponding RollbackException, which might include the specific reason
* (such as a transaction timeout).
* <p>If this method returns "true" but the <code>doCommit</code> implementation does not
* throw an exception, this transaction manager will throw an UnexpectedRollbackException
* itself. This should not be the typical case; it is mainly checked to cover misbehaving
* JTA providers that silently roll back even when the rollback has not been requested
* by the calling code.
* @see #doCommit
* @see DefaultTransactionStatus#isGlobalRollbackOnly()
* @see DefaultTransactionStatus#isLocalRollbackOnly()
* @see org.springframework.transaction.TransactionStatus#setRollbackOnly()
* @see org.springframework.transaction.UnexpectedRollbackException
* @see javax.transaction.UserTransaction#commit()
* @see javax.transaction.RollbackException
*/
protected boolean shouldCommitOnGlobalRollbackOnly() {
return false;
}
/**
* Perform an actual commit of the given transaction.
* <p>An implementation does not need to check the "new transaction" flag
* or the rollback-only flag; this will already have been handled before.
* Usually, a straight commit will be performed on the transaction object
* contained in the passed-in status.
* @param status the status representation of the transaction
* @throws TransactionException in case of commit or system errors
* @see DefaultTransactionStatus#getTransaction
*/
protected abstract void doCommit(DefaultTransactionStatus status) throws TransactionException;
/**
* Perform an actual rollback of the given transaction.
* <p>An implementation does not need to check the "new transaction" flag;
* this will already have been handled before. Usually, a straight rollback
* will be performed on the transaction object contained in the passed-in status.
* @param status the status representation of the transaction
* @throws TransactionException in case of system errors
* @see DefaultTransactionStatus#getTransaction
*/
protected abstract void doRollback(DefaultTransactionStatus status) throws TransactionException;
/**
* Set the given transaction rollback-only. Only called on rollback
* if the current transaction participates in an existing one.
* <p>The default implementation throws an IllegalTransactionStateException,
* assuming that participating in existing transactions is generally not
* supported. Subclasses are of course encouraged to provide such support.
* @param status the status representation of the transaction
* @throws TransactionException in case of system errors
*/
protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException {
throw new IllegalTransactionStateException(
"Participating in existing transactions is not supported - when 'isExistingTransaction' " +
"returns true, appropriate 'doSetRollbackOnly' behavior must be provided");
}
/**
* Register the given list of transaction synchronizations with the existing transaction.
* <p>Invoked when the control of the Spring transaction manager and thus all Spring
* transaction synchronizations end, without the transaction being completed yet. This
* is for example the case when participating in an existing JTA or EJB CMT transaction.
* <p>The default implementation simply invokes the <code>afterCompletion</code> methods
* immediately, passing in "STATUS_UNKNOWN". This is the best we can do if there's no
* chance to determine the actual outcome of the outer transaction.
* @param transaction transaction object returned by <code>doGetTransaction</code>
* @param synchronizations List of TransactionSynchronization objects
* @throws TransactionException in case of system errors
* @see #invokeAfterCompletion(java.util.List, int)
* @see TransactionSynchronization#afterCompletion(int)
* @see TransactionSynchronization#STATUS_UNKNOWN
*/
protected void registerAfterCompletionWithExistingTransaction(Object transaction, List synchronizations)
throws TransactionException {
logger.debug("Cannot register Spring after-completion synchronization with existing transaction - " +
"processing Spring after-completion callbacks immediately, with outcome status 'unknown'");
invokeAfterCompletion(synchronizations, TransactionSynchronization.STATUS_UNKNOWN);
}
/**
* Cleanup resources after transaction completion.
* <p>Called after <code>doCommit</code> and <code>doRollback</code> execution,
* on any outcome. The default implementation does nothing.
* <p>Should not throw any exceptions but just issue warnings on errors.
* @param transaction transaction object returned by <code>doGetTransaction</code>
*/
protected void doCleanupAfterCompletion(Object transaction) {
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization; just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.logger = LogFactory.getLog(getClass());
}
/**
* Holder for suspended resources.
* Used internally by <code>suspend</code> and <code>resume</code>.
*/
protected static class SuspendedResourcesHolder {
private final Object suspendedResources;
private List suspendedSynchronizations;
private String name;
private boolean readOnly;
private Integer isolationLevel;
private boolean wasActive;
private SuspendedResourcesHolder(Object suspendedResources) {
this.suspendedResources = suspendedResources;
}
private SuspendedResourcesHolder(
Object suspendedResources, List suspendedSynchronizations,
String name, boolean readOnly, Integer isolationLevel, boolean wasActive) {
this.suspendedResources = suspendedResources;
this.suspendedSynchronizations = suspendedSynchronizations;
this.name = name;
this.readOnly = readOnly;
this.isolationLevel = isolationLevel;
this.wasActive = wasActive;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -