一、spring IOC容器会为添加了@Transaction注解的方法进行事务增强(动态代理)
在调用方法之前会调用TransactionInterceptor的invoke方法:
又会调用到父类TransactionAspectSupport的invokeWithinTransaction方法,主要关注createTransactionIfNecessary
进入该方法会调用PlatformTransactionManager#getTransaction方法获取TransactionStatus:
二、Connection绑定
PlatformTransactionManager是spring事务的高级抽象,事务的实现需要借助PlatformTransactionManager完成,接下来就看一下AbstractPlatformTransactionManager#getTransaction源码:
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
//transaction类型:DataSourceTransactionManager.DataSourceTransactionObject
//注意 DataSourceTransactionObject的数据结构,DataSourceTransactionObject包含一个ConnectionHolder
// 此时会
Object transaction = doGetTransaction();
if (definition == null) {
// 如果传入的事务定义实例为null的话则创建一个默认的事务定义实例
definition = new DefaultTransactionDefinition();
}
if (isExistingTransaction(transaction)) {
// 事务传播行为有关的的处理
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// 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);
//重重之重的代码,完成创建数据库连接绑定以及设置自动提交为False以及
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.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
doGetTransaction方法会尝试获取连接,如果当前线程没有绑定Connection的话则返回null,org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction源码如下:
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 重点代码,使用TransactionSynchronizationManager获取上下文是否有Connection
//TransactionSynchronizationManager获取连接是借助ThreadLocal实现的
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
在doGetTransaction如果当前没有绑定连接的话,则需要给当前线程绑定一个连接;org.springframework.transaction.support.AbstractPlatformTransactionManager#doBegin方法是事务的基础,接下里以DataSourceTransactionManager实现为例,查看一下源码:
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
// DataSourceTransactionObject持有数据库连接ConnectionHolder成员
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (txObject.getConnectionHolder() == null ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 上下文没有获取到Connection,因此需要在数据库连接池中获取一个Connection 并设置到事务对象中
// 但是由于该连接并没有和线程绑定因此需要跟线程绑定,下文TransactionSynchronizationManager.bindResourc方法绑定到线程
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);
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);
}
// 将连接跟当前线程进行绑定
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.dataSource);
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
到此为止就完成了当前线程的Connection绑定,主要关注TransactionSynchronizationManager#bindResource方法,传入两个参数:分别是DataSource与ConnechtionHolder,这是为了避免一个线程处理多个连接池的Connection时候出错而设置,这样获取连接时候会根据线程与连接池共同为key获取对应的唯一Connection。在Connection绑定时TransactionSynchronizationManager是一个重要的工具。
三、Mapper调用(动态代理)
最终会调用SqlSessionTemplate.sqlSessionProxy相应方法,由于sqlSessionProxy也是代理对象:
最终会调用SqlSessionInterceptor#invoke方法:
会调用SqlSessionUtils#getSqlSession方法获取SqlSession:
从源代码中知道真正的SqlSessionFactory使用的是org.apache.ibatis.session.defaults.DefaultSqlSessionFactory的实例,同时,事务管理使用org.mybatis.spring.transaction.SpringManagedTransactionFactory
重点关注Executor,SqlSession会通过Executor调用数据库,而Executor会通过SpringManagedTransaction#openConnection获取数据库连接
此处以查询举例,会调用Executor#doQuery方法:
最终会调用DataSourceUtils#doGetConnection获取
真正的数据库连接,其中TransactionSynchronizationManager中保存的就是方法调用前,spring增强方法中绑定到线程的connection,从而保证整个事务过程中connection的一致性