Spring事务管理

1. 概念

什么是事务?事务指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败。

事务包括四大特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

  1. 原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  2. 一致性:指事务前后数据的完整性必须保持一致。
  3. 隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间的数据要相互隔离。
  4. 持久性:指一个事务一旦被提交,它对数据库中的数据的改变就是永久的,即使数据库发生故障也不应该对其有任何影响。

2. 事务的API

2.1 接口介绍

Spring对事务管理提供了接口支持,主要包括3个高层抽象的接口:

  1. PlatformTransactionManager事务管理器
  2. TransactionDefinition 事务定义信息(隔离、传播、超时、只读)
  3. TransactionStatus事务具体的运行状态信息(是否新事务、是否有保存点。。。)
Spring事务管理_第1张图片
Spring事务主要接口
2.2 PlatformTransactionManager接口

Spring为不同的持久化框架提供了不同的PlatformTransactionManager接口实现:

Spring事务管理_第2张图片
PlatformTransactionManager主要实现
具体实现 说明
org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring JDBC或Mybatis进行持久化数据是使用
org.springframework.orm.hibernate5.HibernateTransactionManager 使用Hibernate5.x版本进行持久化数据时使用
org.springframework.orm.jpa.JpaTransactionManager 使用JPA进行持久化时使用
org.springframework.orm.jdo.JdoTransactionManager 当持久化机制是Jdo时使用
org.springframework.transaction.jta.JtaTransactionManager 使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用
2.3 TransactionDefinition接口
Spring事务管理_第3张图片
TransactionDefinition接口

TransactionDefinition接口中主要定义了事务的传播行为getPropagationBehavior()、事务的隔离级别getIsolationLevel()、超时时间getTimeout()、是否只读isReadOnly()、事务名称getName()

2.3.1 TransactionDefinition定义事务隔离级别

我们知道事务4个特性中有一个隔离性,如果不考虑隔离性的的话,会引发一些安全问题:脏读不可重复读幻读

  1. 脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
  2. 不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同
  3. 幻读:一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了。在后来的查询中,第一个事务就会发现有些原来没有的记录

隔离级别就是用来解决上述各种问题的,隔离级别有4种(上图中的ISOLATION_*** 除了ISOLATION_DEFAULT):

隔离级别 含义
DEFAULT 使用后端数据库默认的隔离级别(Spring中的选择项)
READ_UNCOMMITTED 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
READ_COMMITTED 允许在并发事务已经提交后读取。可防止脏读,但幻读、不可重复读仍可发生
REPEATABLE_READ 对相同的字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生
SERIALIZABLE 完全服从ACID的隔离级别,确保不发送脏、幻、不可重复读。这仔所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表完成的。
2.3.2 TransactionDefinition定义事务传播行为

事务的传播行为解决的是业务层方法之间调用的时事务的传递问题。

一般我们的系统会分为3层:Web层、业务层Service、持久层DAO;假设有两个业务类ServiceAServiceBServiceA中有方法aaa(),ServiceB中有方法bbb(),有一个业务逻辑需要调用ServiceA.aaa()ServiceB.bbb()才能完成,现在aaa()方法里有事务,bbb()方法里也有事务,那到底要用哪个呢,这就涉及到了事务的传播行为。

事务的传播行为有7种(上图中的PROPAGATION_***):

隔离级别 含义
PROPAGATION_REQUIRED 支持当前事务,如果不存在,就新建一个
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务的方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务的方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
2.4 TransactionStatus接口
Spring事务管理_第4张图片
TransactionStatus接口

事务本身会存在一些状态信息,而TransactionStatus接口里面提供了一些方法,通过这些方法可以获得事务相应的状态。

isNewTransaction():判断是否是一个新的事务
hasSavepoint():是否存在保存点
setRollbackOnly():设置为只回滚
isRollbackOnly():是否为只回滚
isCompleted():是否已完成

3. 编程式事务管理(不常用)

编程式事务管理使用TransactionTemplate模板来控制事务。TransactionTemplate的重要方法就是 execute方法,此方法调用 TransactionCallback 进行处理。实际上我们需要处理的事情全部都是在TransactionCallback中编码的,我们可以定义一个类并实现此接口,然后作为 TransactionTemplate.execute的参数。把需要完成的事情放到doInTransaction中,并且传入一个 TransactionStatus参数,此参数是来调用回滚的。demo如下:

spring配置文件springDemo1.xml

    


    Spring Configuration

    
    

    
    


    
    
        
        
        
        
        
        
    

    
        
    

    

    
    
        
    

    
    
        
    

模拟业务方法AccountServiceImpl.transfer:

/**
     * 模拟转账操作
     * @param out   :转出账号
     * @param in    :转入账号
     * @param money :转账金额
     */
    public void transfer(final String out,final String in,final Double money) {

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try { //具体业务代码
                    accountDaoImpl.outMoney(out,money); //out账户出账
                    //int i = 1/0;
                    accountDaoImpl.inMoney(in,money);// in账户入账
                }catch (Exception e){
                    status.setRollbackOnly(); //设置回滚
                    e.printStackTrace();
                }
            }
        });
    }

4. 声明式事务管理

4.1 声明式事务管理方式一:基于TransactionProxyFactoryBean的方式

spring配置文件springDemo2.xml关键配置:

    

    
    
        
    

    
    
        
        
        
        
        
        
            
                
                PROPAGATION_REQUIRED
                
                
            
        
    

模拟业务方法AccountServiceImpl.transfer:

  public void transfer(final String out,final String in,final Double money) {
        accountDaoImpl.outMoney(out,money);
        accountDaoImpl.inMoney(in,money);
    }
4.2 声明式事务管理方式二:基于AspectJ的XML方式

spring配置文件springDemo3.xml关键配置:

    

    
    
        
    

    
    
        
            
            
        
    

    
    
        
        
        
        
    

模拟业务方法AccountServiceImpl.transfer:

public void transfer(final String out,final String in,final Double money) {
        accountDaoImpl.outMoney(out,money);
        accountDaoImpl.inMoney(in,money);
    }
4.3 声明式事务管理方式三:基于注解的方式(推荐)

这种方式是基于@Transactional注解的,简单易用,更清爽,是推荐的使用方式。

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

@Transactional的属性:

属性 类型 描述
value String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean 读写或只读事务,默认读写
timeout int (in seconds granularity) 事务超时时间设置
rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

spring配置文件springDemo4.xml关键配置:

    

    
    
        
    

    
    

模拟业务方法AccountServiceImpl.transfer:

    @Transactional(readOnly = false)
    public void transfer(final String out,final String in,final Double money) {
        accountDaoImpl.outMoney(out,money);
        accountDaoImpl.inMoney(in,money);
    }

以上示例源码:learn-spring-transaction

你可能感兴趣的:(Spring事务管理)