Java的@Transactional事务回滚
@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事务回滚相关推荐
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除 ...
- java中的事务回滚_Spring中的事务回滚机制
问题:在Java项目汇中,添加@Transactional注解,报错之后,事务回滚未生效,数据仍插入数据库中.经查看报错位置位于新增成功之后.空指针异常. 一.特性 先了解一下@Transaction ...
- @Transactional事务回滚使用
使用:作用于类时,对该类下所有public方法都有效,也可写在某个方法上,当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息 回滚方式: ...
- java pg数据库事务回滚,基于Postgresql 事务的提交与回滚解析
用过oracle或mysql的人都知道在sqlplus或mysql中,做一个dml语句,如果发现做错了,还可以rollback;掉,但在PostgreSQL的psql中,如果执行一个dml,没有先运行 ...
- java的oracle事务回滚_Oracle事务处理
二.事务和锁 当执行事务操作时(dml语句),oracle会在被作用的表上加锁,防止其它用户修改表的结构.这里对我们的用户来讲是非常重要的. 三.提交事务 当用commit语句执行时可以提交事务.当执 ...
- java pg数据库事务回滚_PG 事务提交与回滚
在PostgreSQL中,如果执行一个dml或ddl语句,默认一执行完就马上提交了,不能回滚,这样容易导致误操作的发生,避免这个风险的办法是关闭自动提交 1 设置\set AUTOCOMMIT off ...
- java pg数据库事务回滚_PostgreSQL事务特性之ROLLBACK
一.回滚DDL 1. 回滚表的创建 postgres=# begin; BEGIN postgres=# create table test (id int, name text); CREATE T ...
- java 事务 回滚
给java后台方法添加事务回滚注解,在方法进行多表的增删改查的时候,如果失败可以对此方法前面的一些更新数据库表的语句进行撤销(回滚) 注解:@Transactional(rollbackFor = E ...
- java 事务回滚注解_Java Spring 事务回滚详解
这篇文章主要介绍了java Spring事务回滚的相关资料,需要的朋友可以参考下 spring 事务回滚 1.遇到的问题 当我们一个方法里面有多个数据库保存操作的时候,中间的数据库操作发生的错误.伪代 ...
最新文章
- tensorfllow MNIST机器学习入门
- 保护DNS对数字网络安全越来越重要—Vecloud
- [翻译]Global Descriptor Table-GDT
- ASP程序中调用函数Now()显示上午下午的问题
- 浅析商业银行“业务连续性管理体系”的构建
- Android的sqlite使用外部,Android 使用外部已经建立好的sqlite数据库
- 如何在Windows的PHPstudy中使用redis数据库
- hive on tez集成完整采坑指南(含tez-ui及安全环境)
- paip.判断文件是否存在uapi python php java c#
- plsql导出表结构到excel_PLSQL怎样导出oracle表结构
- Markdown编辑器修改插入图片的大小
- 用这个C语言骰子代码做选择
- 如何在 Linux 中创建并运行 Shell 脚本(Bash 初学者教程)
- 高斯计校准与计量的区别
- 怎样安装linux系统
- 再战Trojan.PSW.Lmir.kuo、Trojan.PSW.Misc.kcc等网游盗号木马(第2版)
- linux脚本小游戏,shell脚本(shopping小游戏)
- Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建高性能Web服务器
- 赣南师大计算机科学学院,徐会林 - 赣南师范大学 - 数学与计算机科学学院
- Flink v1.11 - 官网 - 部署与运维