spring事務傳播實現原始碼分析
本文只是對spring事務傳播實現的流程進行簡單的分析,如有不對之處請指出。
配置spring事務管理時,我們會使用DataSourceTransactionManager這個類,它繼承了AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager實現了PlatformTransactionManager介面,PlatformTransactionManager介面是spring事務管理的基礎介面,只有三個方法getTransaction()、commit()和rollback()。
通過註解@Transactional,我們就可以把事務交由spring管理。spring是通過代理的方式對其新增事務管理,在生成的代理物件中就會呼叫PlatformTransactionManager實現類的三個方法來獲取事務、提交事務、回滾事務,從而達到事務管理的目的。其中獲取事務即呼叫getTransaction()方法,改方法中就會對事務的傳播做相應的處理。
1、getTransaction()方法
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();// 獲取事務管理物件,從下面doGetTransaction()實現可以知道,這裡是嘗試獲取已有的事務管理物件,這裡已有的就是指“傳播”來的事務。
..............................
if (isExistingTransaction(transaction)) { //判斷該事務管理物件是否已經存在
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
..................................
// No existing transaction found -> check propagation behavior to find out how to proceed.
// 根據不同事務傳播屬性進行不同的處理
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition); // 新起一個事務
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
2、 doGetTransaction()方法
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// TransactionSynchronizationManager裡面通過ThreadLocal變數儲存了dataSource對應的ConnectionHolder ,如果ConnectionHolder存在且啟用就表明有“傳播”來的事務。
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
// 順便提下,其它ORM框架就是通過TransactionSynchronizationManager.getResource(dataSource)獲取資料庫連線,以此到達事務交由spring管理的目的。
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
3、 isExistingTransaction()方法
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
//ConnectionHolder存在且啟用就表明有“傳播”來的事務。
return (txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive());
}
4、 doBegin()方法
// 這裡是新起一個事務,為事務管理物件設定相應的值,包括ConnectionHolder、隔離等級、是否自動提交等,並把當前執行緒與ConnectionHolder和dataSource進行繫結。
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the session holder to the thread.
if (txObject.isNewConnectionHolder()) {
//把當前執行緒與ConnectionHolder和dataSource進行繫結,在上面的doGetTransaction()中就可以對應獲取,即到達事務傳播的目的。
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
DataSourceUtils.releaseConnection(con, this.dataSource);
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}