java笔记java中@Transactional注解的使用及其失效情景

Posted 棉花糖灬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java笔记java中@Transactional注解的使用及其失效情景相关的知识,希望对你有一定的参考价值。

本文转自文章一口气说出 6种,@Transactional注解的失效场景

一、事务

spring中的事务管理机制可以分为编程式事务和声明式事务两种。

  • 编程式事务:指在代码中手动的管理事务的提交、回滚等操作,代码侵入性比较强。
  • 声明式事务: 基于AOP面向切面的,它将具体业务与事务处理部分解耦,代码侵入性很低,所以在实际开发中声明式事务用的比较多。声明式事务也有两种实现方式,是基于TX和AOP的xml配置文件方式,二种就是基于@Transactional注解了。

二、@Transactional注解

1. 用法

@Transactional注解可以作用在类、接口、方法上。

  • 作用于类:表示该类的所有public方法都配置了事务。
  • 作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效。
  • 作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。

2. @Transactional的属性

(1) propagation属性

表示事务的传播行为,其取值如下:

  • Propagation.REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。 为默认值。
  • Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
  • Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
  • Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。
  • Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。
  • Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。
  • Propagation.NESTED :和Propagation.REQUIRED效果一样。

(2) isolation属性

表示事务的隔离级别,其取值如下:

  • solation.DEFAULT:使用底层数据库默认的隔离级别。为默认值。
  • Isolation.READ_UNCOMMITTED:未提交读。
  • Isolation.READ_COMMITTED:提交读。
  • Isolation.REPEATABLE_READ:可重复读。
  • Isolation.SERIALIZABLE:序列化。

(3) timeout属性

事务的超时时间,默认为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。

(4) readOnly属性

指定事务是否为只读事务,默认值为false,当为true时可以忽略那些不需要事务的方法,如读取数据。

(5) rollbackFor属性

用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。

(6) noRollbackFor属性

抛出指定的异常类型,不回滚事务,可以指定多个异常类型。

3. @Transactional失效的场景

(1) 应用在非public 方法上时

protectedprivate修饰的方法上使用@Transactional注解,虽然事务无效,但不会有任何报错。

(2) propagation属性设置错误

若是错误的配置以下三种 propagation,事务将不会发生回滚:

  • Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
  • Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。
  • Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。

(3) rollBackFor属性设置错误

Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定rollbackFor属性。

(4) 调用同一个类中的方法时

如果类中的方法A()调用同一个类中的方法B(),且方法A()没有声明事务,而方法B()声明了事务,那么在外部调用方法A()时,方法B()的事务是无效的。

这是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。

(5) 异常被catch捕获导致注解失效

在方法A()上加了@Transactional注解,同时A()方法中调用方法B(),若方法B()抛出的异常被A()方法的catch捕获时,事务将不能正常回滚。

处理方法为:在catch块中再把注解中指定的异常抛出,若没指定异常,则可以抛出throw new RuntimeException()。或者直接不用try-catch代码块。

(6) 数据库引擎不支持事务

常用的mysql数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。

以上是关于java笔记java中@Transactional注解的使用及其失效情景的主要内容,如果未能解决你的问题,请参考以下文章

Java Spring @Transactional 防止并发

美团一面:@Transactional 原理和常见的坑?

美团一面:@Transactional 原理和常见的坑?

如何在 Java 中仅更新 @Transactional 方法中更改的字段?

@Transactional有两个来源包,该导入哪一个?

Java笔记-解决Cause: java.sql.SQLException: 试图在只读事务中修改数据(达梦数据库)