@Transactional是基于AOP的,因此事务发生需要两个条件:

1.添加@Transactional注解

2.使用代理对象

失效场景:同一个类中直接调用的类方法,而被调方法带有@Transactional

下面这段代码会抛出runtimeException异常,但是事务不会回滚。即insert生效了

因为b()在调用a()方法时,对象已经不再是代理对象,而是普通对象。而aop都是基于代理对象实现的,即aop是不关心普通对象头顶上注解的,因此事务会失效

@Transactional
public void a(){
int insert = mapper.insert(Entity);
if(insert<=0)
throw new RuntimeException("插入信息失败!");

}
public void b(){
a();
}

如果我们将代码块修改为下面这样,那么他是可以正常回滚的。此时其实只是发生了b()的回滚,因为a()抛出了异常给b()。如果这样写,其实a()的注解是无效的。达不到预期缩减事务代码块的目的


@Transactional
public void a(){
int insert = mapper.insert(Entity);
if(insert<=0)
throw new RuntimeException("插入信息失败!");

}
@Transactional
public void b(){
a();
}

解决办法:

那么如何让a()方法事务能够回滚呢?触发的两个条件,我们已经具备了第一个添加@Transactional注解,但是目前是普通的对象,而非代理对象。因此我们需要让a()由代理对象来实现

下例中,我们将a()方法写入service接口,然后通过注册一个本方法的bean,实现了代理对象,满足上述条件,可以对a()单独实现回滚

@Autowired
Service service;
@Transactional
public void a(){
int insert = mapper.insert(Entity);
if(insert<=0)
throw new RuntimeException("插入信息失败!");

}
public void b(){
service.a();
}

除此以外,还有一些其他让事务不能回滚的原因:

1.a()方法是private或者final的

我们知道,aop的实现是基于代理对象的。上述解决办法中,如果我们没有区分出impl。

那么一旦a方法私有化或者不可变的,会导致代理对象作为普通对象的子类,没有权限去通过AOP重写方法,会导致爆出空指针异常

2.数据库不支持事务、没有bean化的类:神仙难救

3.如果没有捕获到runtime或者error,spring是不会触发回滚的。

关于这点阿里规范中要求在@Transactional中指定rollbackFor,合理使用一般不会出现这个问题

还有如果仅仅是捕获了异常而没有抛出,那么也是不会触发回滚的

springboot中事务失效的一些场景以及如何应对的更多相关文章

  1. SpringBoot中常见的各种初始化场景分析

    大家能区分出以下各种初始化适用的场景吗 ApplicationRunner,CommandLineRunner,BeanFactoryPostProcessor,InitializingBean,Be ...

  2. 就这?Spring 事务失效场景及解决方案

    小明:靓仔,我最近遇到了很邪门的事. 靓仔:哦?说来听听. 小明:上次看了你的文章<就这?一篇文章让你读懂 Spring 事务>,对事务有了详细的了解,但是在项目中还是遇到了问题,明明加了 ...

  3. 聊聊spring事务失效的12种场景,太坑了

    前言 对于从事java开发工作的同学来说,spring的事务肯定再熟悉不过了. 在某些业务场景下,如果一个请求中,需要同时写入多张表的数据.为了保证操作的原子性(要么同时成功,要么同时失败),避免数据 ...

  4. @Transactional注解事务失效的几种场景及原因

    1. 介紹 在业务开发的许多场景中,我们会使用到通过事务去控制多个操作的一致性.比较多的就是通过声明式事务,即使用 @Transactional 注解修饰方法的形式.但在使用过程中,要足够了解事务失效 ...

  5. SpringBoot 注解事务声明式事务

    转载请注明: http://www.cnblogs.com/guozp/articles/7446477.html springboot 对新人来说可能上手比springmvc要快,但是对于各位从sp ...

  6. 面试突击83:什么情况会导致@Transactional事务失效?

    一个程序中不可能没有事务,而 Spring 中,事务的实现方式分为两种:编程式事务和声明式事务,又因为编程式事务实现相对麻烦,而声明式事务实现极其简单,所以在日常项目中,我们都会使用声明式事务 @Tr ...

  7. SpringBoot设置事务管理

    关于事务就不介绍了,前面在研究spring的时候就已经研究过了,参考:https://www.cnblogs.com/qlqwjy/p/7296493.html 这里直接研究springboot中事务 ...

  8. Spring事务Transactional和动态代理(三)-事务失效的场景

    系列文章索引: Spring事务Transactional和动态代理(一)-JDK代理实现 Spring事务Transactional和动态代理(二)-cglib动态代理 Spring事务Transa ...

  9. 在springBoot与quartz 整合中 @Transaction 失效

    问题1::springBoot在与quartz 整合时,使用@Transaction 注解时事务失效 解决方案:创建一个类使用@component被spring管理 ,使用@Transaction标识 ...

  10. [SpringBoot]SpringBoot中使用redis事务

    本文基于SpringBoot 2.X 事务在关系型数据库的开发中经常用到,其实非关系型数据库,比如redis也有对事务的支持,本文主要探讨在SpringBoot中如何使用redis事务. 事务的相关介 ...

随机推荐

  1. Android 12(S) MultiMedia Learning(三)MediaPlayer Native

    上一篇MediaPlayer中看到实现一个最简单的播放器只需要5个接口,接下来会看看这些接口实现内容 /************************************************ ...

  2. 一分钟部署prometheus&grafana全方面监控SpringBoot项目

    0x01 创建目录 找一个你喜欢的地方,创建项目根目录 example: [root@demo-78 ~]# mkdir /data/prometheus 0x02 创建配置文件 进入到项目根目录: ...

  3. k8s——kubctl命令基础

    语法 kubevtl [command] [type] [name] [flags] command: 指定要对一个或多个资源执行的操作,例如,`create`,`get`,`describe`,`d ...

  4. switch的穿透

      // switch 的 穿透         // 什么是switch的穿透         // 如果在 switch 中没有定义break , switch 会从定位的程序,一直执行到所有sw ...

  5. pyenv-win 替换国内镜像源

    前情提要 今天心血来潮想学一学python 然后因为python版本众多,了解到了pyenv这个python版本管理器 在github下载好pyenv以后,打算先安装一个稳定的版本 pyenv ins ...

  6. spring项目中读取resources下的文件

    spring项目中读取resources下的文件 我们都知道,spring项目经过maven打包后,可以打成jar包或可解压的war包 a. war包是需要外置的web容器去运行的,是需要先解压的 b ...

  7. Flink状态(二)

    Flink提供了不同的状态存储方式,并说明了状态如何存和存储在哪里. 状态可以被存储在Jvm的堆和堆外.根据状态存储方式的不同,Flink也能代替应用管理状态,意思是Flink能够进行内存管理(有必要 ...

  8. Spring Boot入门实验

    一. 实验目的和要求 1.掌握使用 IDEA 通过 Maven 和 Spring Initializr 的方式创建 Spring Boot 应用程序: 2.掌握 Maven 的工作原理: 3.了解 s ...

  9. injectionIII iOS代码注入工具(上)

    injectionIII iOS代码注入工具(上) 前言 如果之前用过injection的朋友一定会对其热重载的特性印象深刻,如今injection经过多次更新,现在以injectionIII之名上架 ...

  10. spring使用RedisCacheManager管理key的一些问题

    spring可以很好地管理各种内存的快速缓存. 这些常见的内存缓存库实现方式有redis,Ehcache. 本文阐述的是redis,毕竟这个东西相当容易使用. spring通过 org.springf ...