@Transactional 基本原理概述

在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。

处理Springboot下提交事务异常,数据库没有回滚的问题

Spring文档中说道,Spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作。

什么是检查型异常和非检查型异常?

最简单的判断点有两个:
1、继承自runtimeException或error的是非检查型异常,而继承自exception的是检查型异常。
2、对非检查型异常可以不用捕获,而检查型异常必须用try语句块进行处理或者把异常交给上级方法处理,总之就是必须写代码处理它。所以必须service捕获异常,然后再次抛出,这样事务才能生效。

默认规则:

1、让检查型异常也回滚,@Transactional(rollbackFor=Exception.class),一般只需添加这个即可

2、让非检查型异常不回滚,@Transactional(notRollbackFor=RunTimeException.class)

3、不需要事务管理的(就是只是查询用)方法,@Transactional(propagation=Propagation.NOT_SUPPORTED),或者不添加

4、手动回滚,TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
例如:

try {String name = (String) list.get(j - 1).get("name");} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return ResultUtil.error(500, "文件解析错误");}

你需要注意的事

1.@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能
2.Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。
3.当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,还是在具体的类上使用 @Transactional 注解比较好。
4.避免 Spring 的 AOP 的自调用问题:自调用就是方法A内调用本类的另一个加上事务注解的方法B时,方法B中对数据库的操作是不带事务的。

Spring AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。
失效原因:

方法one方法two都是public的:

classA中 ,任意要调用classB的方法,是通过spring代理的方式,那么spring的注解才会生效
classA中,方法one 调用同class内的方法two,即this调用,spring注解不会生效(例如@Cachable,@Transaction)

解决方法

方案一:使用AspectJ代理

@Service
public class OrderService {private void insert() {insertOrder();}
@Transactionalpublic void insertOrder() {//insert log info//insertOrder//updateAccount}
}

insertOrder 尽管有@Transactional 注解,但它被内部方法 insert 调用,事务被忽略,出现异常事务不会发生回滚。

上面的两个问题@Transactional 注解只应用到 public 方法和自调用问题,是由于使用 Spring AOP 代理造成的。为解决这两个问题,可以使用 AspectJ取代 Spring AOP 代理,但现在有更好的解决方法。

方案二:利用AopContext.currentProxy()方法获得代理

方法的意思是尝试返回当前AOP代理。这种做法非常简洁,但是在默认情况下是不起作用的!因为AopContext中拿不到currentProxy,会报空指针。需要一些额外的配置,但不能对所有的注解拦截都有效,这是因为这些注解不是用的AspectJ代理,如果是@Transactional事务注解的话, 则是生效的,具体细节要翻源码了,这里不推荐使用。

方案三:通过ApplicationContext来获得动态代理对象(推荐)

@Component
public class AsyncService implements ApplicationContextAware {private ApplicationContext applicationContext;public void async1() {System.out.println("1:" + Thread.currentThread().getName());// 使用AppicationContext来获得动态代理的bean,然后再执行你调用的方法this.applicationContext.getBean(AsyncService.class).async2();}@Asyncpublic void async2() {System.out.println("2:" + Thread.currentThread().getName());}// 注入ApplicationContext@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

Java的@Transactional事务回滚相关推荐

  1. Spring中@Transactional事务回滚(含实例详细讲解,附源码)

    一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除 ...

  2. java中的事务回滚_Spring中的事务回滚机制

    问题:在Java项目汇中,添加@Transactional注解,报错之后,事务回滚未生效,数据仍插入数据库中.经查看报错位置位于新增成功之后.空指针异常. 一.特性 先了解一下@Transaction ...

  3. @Transactional事务回滚使用

    使用:作用于类时,对该类下所有public方法都有效,也可写在某个方法上,当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息 回滚方式: ...

  4. java pg数据库事务回滚,基于Postgresql 事务的提交与回滚解析

    用过oracle或mysql的人都知道在sqlplus或mysql中,做一个dml语句,如果发现做错了,还可以rollback;掉,但在PostgreSQL的psql中,如果执行一个dml,没有先运行 ...

  5. java的oracle事务回滚_Oracle事务处理

    二.事务和锁 当执行事务操作时(dml语句),oracle会在被作用的表上加锁,防止其它用户修改表的结构.这里对我们的用户来讲是非常重要的. 三.提交事务 当用commit语句执行时可以提交事务.当执 ...

  6. java pg数据库事务回滚_PG 事务提交与回滚

    在PostgreSQL中,如果执行一个dml或ddl语句,默认一执行完就马上提交了,不能回滚,这样容易导致误操作的发生,避免这个风险的办法是关闭自动提交 1 设置\set AUTOCOMMIT off ...

  7. java pg数据库事务回滚_PostgreSQL事务特性之ROLLBACK

    一.回滚DDL 1. 回滚表的创建 postgres=# begin; BEGIN postgres=# create table test (id int, name text); CREATE T ...

  8. java 事务 回滚

    给java后台方法添加事务回滚注解,在方法进行多表的增删改查的时候,如果失败可以对此方法前面的一些更新数据库表的语句进行撤销(回滚) 注解:@Transactional(rollbackFor = E ...

  9. java 事务回滚注解_Java Spring 事务回滚详解

    这篇文章主要介绍了java Spring事务回滚的相关资料,需要的朋友可以参考下 spring 事务回滚 1.遇到的问题 当我们一个方法里面有多个数据库保存操作的时候,中间的数据库操作发生的错误.伪代 ...

最新文章

  1. tensorfllow MNIST机器学习入门
  2. 保护DNS对数字网络安全越来越重要—Vecloud
  3. [翻译]Global Descriptor Table-GDT
  4. ASP程序中调用函数Now()显示上午下午的问题
  5. 浅析商业银行“业务连续性管理体系”的构建
  6. Android的sqlite使用外部,Android 使用外部已经建立好的sqlite数据库
  7. 如何在Windows的PHPstudy中使用redis数据库
  8. hive on tez集成完整采坑指南(含tez-ui及安全环境)
  9. paip.判断文件是否存在uapi python php java c#
  10. plsql导出表结构到excel_PLSQL怎样导出oracle表结构
  11. Markdown编辑器修改插入图片的大小
  12. 用这个C语言骰子代码做选择
  13. 如何在 Linux 中创建并运行 Shell 脚本(Bash 初学者教程)
  14. 高斯计校准与计量的区别
  15. 怎样安装linux系统
  16. 再战Trojan.PSW.Lmir.kuo、Trojan.PSW.Misc.kcc等网游盗号木马(第2版)
  17. linux脚本小游戏,shell脚本(shopping小游戏)
  18. Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建高性能Web服务器
  19. 赣南师大计算机科学学院,徐会林 - 赣南师范大学 - 数学与计算机科学学院
  20. Flink v1.11 - 官网 - 部署与运维

热门文章

  1. 幸福人生讲座(十):五伦中哪一伦最重要?
  2. 从头用脚分析FFmpeg源码 - av_interleaved_write_frame | av_write_frame
  3. 详解服务器、磁盘和网卡知识
  4. 网络游戏侵权案件有哪些
  5. mysql查询数据库每张表数据量大小和占用多少空间
  6. 初中级php程序员面试时常见问题整理
  7. 求解求最大公约数定义的算法,这个程序求不出来,网上百度的算法不对?
  8. 阻燃等级UL94是做哪些测试?
  9. 爬虫自学day4:requests模块之爬取豆瓣电影分类排行榜
  10. 【Linux】Linux进程概念(学习复习兼顾)