天天看点

SpringBoot 事务(@Transactional)整合Spring boot 事务整合数据库的四种隔离级别Spring中七种事务传播行为

SpringBoot 事务(@Transactional)整合

  • Spring boot 事务整合
    • 业务分析
    • 实战编码
  • 数据库的四种隔离级别
  • Spring中七种事务传播行为

Spring boot 事务整合

spring boot 事务是怎么控制的呢?就是我们熟知的

@Transactional

注解了

业务分析

让代码更新信息后抛出异常,看看数据会不会回滚

实战编码

修改更新用户信息接口抛出一个异常

@PutMapping("/user")
    @Transactional(rollbackFor = Exception.class)
    public String updateUser(@RequestBody ApiUserVO vo) {
        int flag = userService.updateUser(vo);
        int i =1/0;
        if (flag <= 0) {
            return "修改失败";
        }
        return "修改成功";
    }
           

抛出异常后数据库并未进行修改;

@Transactional 异常不回滚几种原因

  1. @Transactional是基于AOP动态代理做的,所以方法必须是public;其他的修饰符不生效。
  2. Spring事务控制器在catch里面做了判断只有RuntimeException或者错误信息的时候才会回滚,故不是RuntimeException的异常不会回滚。

Transactional的异常控制,默认是Check Exception 不回滚,unCheck Exception回滚 如果配置了rollbackFor 和 noRollbackFor 且两个都是用同样的异常,那么遇到该异常,还是回滚 rollbackFor 和noRollbackFor 配置也许不会含盖所有异常,对于遗漏的按照Check Exception 不回滚,unCheck Exception回滚。

数据库的四种隔离级别

数据库一共有如下四种隔离级别:

  • Read uncommitted

    读未提交

    在该级别下,一个事务对一行数据修改的过程中,不允许另一个事务对该行数据进行修改,但允许另一个事务对该行数据读。

    因此本级别下,不会出现更新丢失,但会出现脏读、不可重复读。

  • Read committed

    读已提交

    在该级别下,未提交的写事务不允许其他事务访问该行,因此不会出现脏读;但是读取数据的事务允许其他事务的访问该行数据,因此会出现不可重复读的情况。

  • Repeatable read

    可重复读

    在该级别下,读事务禁止写事务,但允许读事务,因此不会出现同一事务两次读到不同的数据的情况(不可重复读),且写事务禁止其他一切事务。

  • Serializable 序列化

    该级别要求所有事务都必须串行执行,因此能避免一切因并发引起的问题,但效率很低。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
隔离级别 脏读 不可重复读 幻读
读未提交(Read uncommitted)
读已提交(Read committed) ×
可重复读(Repeatable read) × ×
可串行化(Serializable ) × × ×

Spring中七种事务传播行为

序号 事务传播行为类型 说明
1 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
2 PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行
3 PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
4 PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
5 PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6 PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
7 PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
可以看出1、2、3为一组,都表现对当前事务的支持,不同的在于当前不存在事务的处理方式;4、5、6为一组,都表现对当前事务的不支持,不同的在于当前有事务的处理方式。然后7单独一组。
举个小栗子,比如有一个service中有方法A,调用了方法B,方法B的传播行为是PROPAGATION_REQUIRED,那么如果方法A的传播行为也是PROPAGATION_REQUIRED,方法A运行的时候,开启了一个事务,方法A中执行到方法B的时候,察觉到当前已经有事务了,方法B就不会再创建新的事务,直接包含在方法A的事务当中。