spring事务原理剖析

来源:互联网 发布:光明数据 东华 编辑:程序博客网 时间:2024/06/05 04:08

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> 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);        }    }
原创粉丝点击