Spring 事务隔离级别 事务传播特性 @Transactional使用

spring的事务处理能力,本质上是数据库提供的。
一个数据库具备事务,那么它必然支持4个特性,

事务的4大特性

  1. 原子性
  2. 一致性
  3. 隔离性
  4. 持久性

这4个特性,保证了数据库处理单事务是有保障的,正确的。更多应用处理场景下,是多事务并行出现的。同时,两个或两个以上的事务,操作同一张表,就会引起冲突。为了解决事务间交互产生的问题,数据库设置了4个隔离级别

数据库的4大隔离级别

  • read uncommitted (读未提交)B事务可以读取到A事务未提交的修改。有脏读的问题
  • read committed (读以提交)B事务不能读取其他事务未commit的修改。有不可重复读,幻读的问题
  • repeated read (可重复读) 事务第一次读和第二次读,结果不受其他事务影响,结果是一样的。有幻读的问题
  • Serializeble (串行化)幻读,比如事务A对表T所有行进行update,再次查询,发现有些行没有update,原因是这些行是新增行,是其他事务添加的,导致不会修改新增的行。串行化,就是顺序执行事务。这个隔离界别要慎用,因为及其影响数据库吞吐量,未能使用到CPU的高性能。

隔离界别,从低到高。级别越高,数据库处理多事务的规则越严格,意味着要牺牲性能为代价。不同的数据库,默认的数据隔离级别有区别,大多数据库默认是repeated read。mysql默认是read committed。

spring的事务隔离级别,本质上是依照数据库来设计的。

spring的5大事务隔离级别

隔离级别含义
ISOLATION_DEFAULT使用后端数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。
ISOLATION_READ_COMMITTED允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。
ISOLATION_REPEATABLE_READ对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻影读仍可能发生。
ISOLATION_SERIALIZABLE完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的

理解数据库隔离级别,自然就明白了设置spring各个事务的原因。

怎么理解事务传播特性?

这要从编程的角度。一个方法执行,在它之间,假如已经创建了事务,那它要创建新事务还是加入原有事务;假如之前没有事务,那它又该如何处理;假如外层事务异常要回滚,内层事务要不要回滚;假如内层事务异常要回滚,外层事务要不要回滚。这就要求必须定义好事务的传播特性,使得程序任一步都知道如何处理事务问题

传播行为意义
PROPAGATION_REQUIRES表示当前方法必须在一个事务中运行。如果一个现有事务正在进行中,该方法将在那个事务中运行,否则就要开始一个新事务。
PROPAGATION_REQUIRES_NEW表示当前方法必须在它自己的事务里运行。一个新的事务将被启动,而且如果有一个现有事务在运行的话,则将在这个方法运行期间被挂起。
PROPAGATION_MANDATORY表示该方法必须运行在一个事务中。如果当前没有事务正在发生,将抛出一个异常
PROPAGATION_NESTED表示如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务不存在,行为就像PROPAGATION_REQUIRES一样。他会和父事务一起commit,当它回滚时,父事务有条件的选择是否跟随回滚,或者继续执行
PROPAGATION_NEVER表示当前的方法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异常。
PROPAGATION_NOT_SUPPORTED表示该方法不应该在一个事务中运行。如果一个现有事务正在进行中,它将在该方法的运行期间被挂起。
PROPAGATION_SUPPORTS表示当前方法不需要事务性上下文,但是如果有一个事务已经在运行的话,它也可以在这个事务里运行。

spring编写事务,有声明式事务和编程式事务,这篇文章,只介绍声明式事务。
声明式事务,先要添加bean配置

<!--  将数据源绑定到事务实现类    -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">       
        <property name="dataSource" ref="dataSource" />       
</bean>
<!-- 开启事务配置 -->   
<tx:annotation-driven/> 

使用注解@Transactional,来声明事务。

@Transactional可以写在任何的类上,要求该类的bean是spring容器管理的。常见的bean是@Controller,@Service,@Repository。有类级别和方法级别的声明。常用spring的猿,我就不多解析了。

@Transactional有两点需要注意

  1. 只能声明在public的method。原因是spring是通过JDK代理或者CGLIB代理的,生成的代理类,只能处理public方法;
  2. 不能被类内部方法调用。还是因为代理的原因,类内部自调用,不会经过代理类,所以@Transactional不会生效
class A {
    @Transactional
    public void method1() {
        method2();
    }
    @Transactional
    public void method2() {
    }
}

method1调用method2,不会触发method2的@Transactional声明。

在常见的ssm系统里,@Transactional会定义在controller的public方法上,因为一次请求往往意味着一连串的数据库操作,使用事务正好,一旦这次请求成功,则全部commit,一旦失败,则全部rooback。

还要继续深入 @Transactional,简单使用 @Transactional,只是使用默认的参数,不能完全满足业务需求。它含有的参数,是用来设置事务隔离级别和传播特性。

@Transactional的参数讲解

参数名称功能描述
readOnly该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
noRollbackFor该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})
propagation该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout该属性用于设置事务的超时秒数,默认值为-1表示永不超时

以上参数大多比较好理解。关注点就在于事务的传播特性,当一个拥有事务的方法调用另外一个事务的方法,要理解好传播特性,才不会导致错误的事务处理。比如使用PROPAGATION_REQUIRES_NEW,事务和事务之间是隔离开的,内层事务失败不会影响外层事务。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值