spring事务原理剖析

本文详细介绍了Spring事务管理的核心概念,包括事务传播和隔离级别,并深入解析了Spring事务的实现原理,涵盖了编程式和声明式的使用方式,以及关键类如PlatformTransactionManager、TransactionDefinition等的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring 事务基本原理

先看看Java JDBC操作数据库的基本步骤

  1. 获取数据库连接 DriverManager.getConnection

  2. 开启事务conn.setAutoCommit()

  3. 执行CRUD

  4. 提交事务|回滚事务conn.commit() / conn.rollback()

  5. 关闭连接 conn.close()

spring事务提供了编程式声明式两种方式。使用spring事务,可以不再写2、4步骤代码,spring事务代理会帮我们自动完成事务开启、正常提交事务or异常回滚事务操作。

这里顺便提下我在学些过程中踩到的坑,MySQL数据库事务回滚对innodb索引有效, 而myisam是不支持事务的, 建表的时候选好索引类型。

  spring 事务原理底层离不开数据库事务的支持。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

spring 事务核心概念

Spring 事务的两大核心 :传播 + 隔离

1.事务传播
事务传播级别解释
PROPAGATION_REQUIRED支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务 拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。
2. 事务隔离

  本质就是数据库隔离级别
spring定义的五种事务隔离级别(本质是4种事务,1种是默认事务,其余四种和数据库的4种事务一一对应)

事务隔离级别解释
ISOLATION_DEFAULTspring 默认事务隔离级别。也是数据库默认的事务隔离级别。
ISOLATION_READ_UNCOMMITTED这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED一个事务只读取另一个事务已提交的数据。保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
ISOLATION_REPEATABLE_READ这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
ISOLATION_SERIALIZABLE这是最可靠的事务隔离级别。事务串行执行(被处理为顺序执行), 对系统的性能影响很大, 谨慎采取此隔离级别

注意:隔离级别越高,越能保证数据一致性,但这是要付出性能代价的。使用事务的时候谨慎选取事务隔离级别。

深入spring 事务原理

事务源码分析:

核心四大类

1) PlatformTransactionManager : spring 事务核心基础接口。主要实现常见有:
  • DataSourceTransactionManager : 适用于使用JDBC和iBatis进行数据持久化操作的情况
  • HibernateTransactionManager :适用于使用Hibernate进行数据持久化操作的情况。
  • JtaTransactionManager:适用于使用JPA进行数据持久化操作的情况。

常用接口:

Public interface PlatformTransactionManager{
  - TransactionStatus getTransaction(TransactionDefinition definition)
  - void commit(TransactionStatus status)
  - void rollback(TransactionStatus status)
}
2) TransactionDefinition : 定义了事务隔离、传播等属性

事务隔离级别: 隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:(有一个默认常量,其实也就是四种隔离级别)

3)TransactionStatus :接口提供了一个简单的控制事务执行和查询事务状态的方法。
public  interface TransactionStatus{
   boolean isNewTransaction();
   void setRollbackOnly();
   boolean isRollbackOnly();
}
4)TransactionTemplate
  • xml config
    <!-- 事物处理器配置 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="应用DBsource"/>
    </bean>

    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager" />
    </bean>
  • spring 编程式事务使用入口
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {

                // todo 这里是业务逻辑code

            }
        });

TransactionTemplate.execute源码分析:
获取TransactionStatus对象, 通过action.doInTransaction(status)回调包裹在事务中的业务逻辑. 如果业务正常, 则提交事务。否则事务异常, 调用rollbackOnException进行回滚, 继续跟进rollbackOnException方法, 底层是通过 conn.rollback() 来回滚的。

@Override
    public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
        }
        else {
            // 获取事务(底层封装了DataSource、connection)
            TransactionStatus status = this.transactionManager.getTransaction(this);
            T result;
            try {
                // action 回调业务逻辑代码
                result = action.doInTransaction(status);
            }
            catch (RuntimeException ex) {
                // Transactional code threw application exception -> rollback
                rollbackOnException(status, ex);
                throw ex;
            }
            catch (Error err) {
                // Transactional code threw error -> rollback
                rollbackOnException(status, err);
                throw err;
            }
            catch (Exception ex) {
                // Transactional code threw unexpected exception -> rollback
                rollbackOnException(status, ex);
                throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
            }
            this.transactionManager.commit(status);
            return result;
        }
    }

getTransaction 方法负责准备事务开启前期等工作。有个比较重要的doBegin方法
把事务自动提交关闭、设置自动超时等

@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);

            // 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()) {
                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);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值