背景
在SpringBoot通常会使用到事务注解快速启动一个事务,但是在一个大型项目中,往往会存在一些流程上的逻辑需要在事务提交之后新启一个方法执行逻辑,比如避免后续逻辑报错影响前面执行的db操作进行事务回滚,伪代码如下:
@Transactional
void funcA(){
funcDB(); // do some db process
logger.info("do some db process");
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
serviceImpl.funcB();
}
}
);
funcC(); // do some db process
}
按照上述代码的执行,整个方法的执行顺序如下: @Transactional切面 -> funcDB()->funcC() -> 切面后置环绕:afterCommit();
源码分析
DataSourceTransactionManager 的实现
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
/** 持有 javax.sql.DataSource对象 */
private DataSource dataSource;
/**
* 这里是产生 Transaction对象 的地方,为 Transaction 的创建提供服务,对数据库而言,
* 事务工作是由 Connection 来完成的。这里把数据库的 Connection对象 放到了 ConnectionHolder 中,
* 然后封装到一个 DataSourceTransactionObject对象 中,在这个封装过程中增加了许多为事务处理服务的
* 控制数据
*/
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 获取与当前线程绑定的数据库Connection,这个 Connection 在第一个事务开始
// 的地方与线程绑定
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
/**
* 判断是否存在活跃的事务,由ConnectionHolder的transactionActive属性 来控制
*/
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive());
}
/**
* 这里是处理事务开始的地方,在这里设置隔离级别,但忽略超时
*/
@Override
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);
// 这里是 数据库Connection 完成事务处理的重要配置,需要把 autoCommit属性 关掉
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);
}
// 把当前的 数据库Connection 与线程绑定
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
DataSourceUtils.releaseConnection(con, this.dataSource);
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
/**
* 事务提交的具体实现
*/
@Override
protected void doCommit(DefaultTransactionStatus status) {
// 取得 Connection 以后,通过Connection 进行提交
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
/**
* 事务提交的具体实现,通过 Connection对象 的 rollback()方法 实现
*/
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
}
相关问题: [[记一次事务的坑:Transaction rolled back because it has been marked as rollback-only]] [[Spring中利用AOP使用自定义注解]]