@Transactional事务注解

  • Post author:
  • Post category:其他




@Transactional事务注解

@Transactional 是一种Spring声明式事务注解

一、在声明式的事务处理中,要配置一个切面,表示如何开启或使用事务。事务传播行为propagation有七种配置:

配置 作用
REQUIRED 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,默认为此
SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行
MANDATORY 支持当前事务,如果当前没有事务,就抛出异常
REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起
NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER 以非事务方式执行,如果当前存在事务,则抛出异常
NESTED 支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务

二、除了配置propagation,还可能需要配置事务隔离级别isolation。在使用事务过程中,通常会发生以下三种情况:

  • 脏读(dirty read):当一个事务读取另一个事务尚未提交的修改时,产生脏读。


脏读:类A中有方法C,类B中有方法D,方法事务传播行为类型都是默认设置(propagation = Propagation.REQUIRED),事务具有传递性,A.C调用B.D方法后,A.C还要查询了B.D中改动的对象E的数据,这时候C拿到的数据是不正确的(是未改动前的数据,因为D更新E的事物还没有提交),即一个事物读取了另一个事物未提交的数据。

  • 不可重复读(non-repeatable read):同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。
  • 幻像读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。
配置 作用
DEFAULT 数据源(数据库)的默认隔离级别,以目前常用的MySQL为例,默认的隔离级别通常为REPEATABLE_READ
READ_UNCOMMITTED 未授权读取级别。这是最低的隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读
READ_COMMITTED 授权读取级别。以操作同一行数据为前提,读事务允许其他读事务和写事务,未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读,但不能防止不可重复读、幻读。此隔离级别可以通过“瞬间共享读锁”和“排他写锁”实现
REPEATABLE_READ 可重复读取级别。保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响。以操作同一行数据为前提,读事务禁止其他写事务,但允许其他读事务,未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读、不可重复读,但不能防止幻读
SERIALIZABLE 序列化级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。提供严格的事务隔离,此隔离级别可以防止更新丢失、脏读、不可重复读、幻读。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免更新丢失、脏读,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制

三、另外还有读写事务控制readOnly

  • readOnly=true表明所注解的方法或类只是读取数据。
  • readOnly=false表明所注解的方法或类是增加,删除,修改数据。默认false


四、在一个Service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务

  • 事务方法A 调用事务方法B,方法B不会开启新的事务
  • 事务方法A 调用方法B, 方法B抛出异常,可回滚
  • 普通方法A 调用事务方法B, 方法B抛出异常,不可回滚


另外,当我们需要在事务控制的service层类中使用try catch 去捕获异常后,就会使事务控制失效,需要手动回滚:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

五、异常回滚

  • @Transactional只能回滚 RuntimeException 和 RuntimeException 子类抛出的异常,不能回滚Exception 异常
  • Exception异常回滚应该使用:@Transactional(rollbackFor = Exception.class)

文章参考:


https://blog.csdn.net/wangpf2011/article/details/87120930



https://blog.csdn.net/cucgyfjklx/article/details/126384760



版权声明:本文为Blair686原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。