spring事务原理剖析

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_DEFAULT spring 默认事务隔离级别。也是数据库默认的事务隔离级别。
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 execute(TransactionCallback 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);
        }
    }

你可能感兴趣的:(Spring)