在工作中,经常会碰到一些事务失效的坑,基于遇到的情况,以及了解到的坑,写了本篇文章与大家学习交流~

1、方法内部调用

非事务方法调用事务方法会出现问题

@Autowired
private KsAService ksAService; public void add() {
this.doAdd();
} @Transactional
public void doAdd() {
KsA ksA = new KsA();
ksA.setName("forlan");
ksAService.insert(ksA);
int res = 1 / 0;
}

原因:Spring声明式事务是基于动态代理(AOP)实现的对bean的管理和切片,为我们每个class生成代理对象,只有代理对象之间调用,才会触发切面逻辑,方法A调用方法B,这里的ksAService是真实对象,不是代理对象

解决:

  • add方法加上注解@Transactional
  • doAdd方法中使用代理对象来调用
    @Transactional
    public void doAdd() {
    KsA ksA = new KsA();
    ksA.setName("forlan");
    KsAService ksAService =(KsAService) AopContext.currentProxy();
    ksAService.insert(ksA);
    int res = 1 / 0;
    }

2、修饰符

@Transactional
private void doAdd() {
KsA ksA = new KsA();
ksA.setName("forlan");
ksAService.insert(ksA);
int res = 1 / 0;
}

原因:Spring声明式事务是基于动态代理实现

  • 非public修饰,不能被代理
  • static修饰的方法属于类,不属于对象,不能被重写,不能被代理
  • final修饰的方法不能被重写,不能被代理

解决:不使用这些修饰符,非public、static、final

  • static、final,代理里面一般有提示,Methods annotated with ‘@Transactional’ must be overridable
  • 注意不要使用非public修饰,特别是private,我们很习惯性写成这个

3、非运行时异常

@Transactional
public void doAdd() throws IOException{
KsA ksA = new KsA();
ksA.setName("forlan");
ksAService.insert(ksA);
throw new IOException();
}

原因:使用Spring的@Transactiona开启事务,默认Error和RuntimeException及其子类才会回滚
解决:指定异常回滚@Transactional(rollbackFor = Exception.class)

4、try…catch捕获异常

@Transactional
public void doAdd() throws RuntimeException {
KsA ksA = new KsA();
ksA.setName("forlan");
ksAService.insert(ksA);
try {
int res = 1 / 0;
} catch (Exception e) {
// 抛出异常
// 设置手动回滚
}
}

原因:自己捕获了异常,则事务无法感知

解决:

  • 抛出异常:throw new RuntimeException(e.getMessage());
  • 设置手动回滚:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

5、多线程调用

@Transactional
public void doAdd() {
new Thread(() -> {
KsA ksA = new KsA();
ksA.setName("forlan");
ksAService.insert(ksA);
}).start();
int res = 1 / 0;
}

原因:因为Spring的事务是通过数据库连接来实现不同线程使用不同的数据库连接,放在ThreadLocal中,基于同一数据库连接的事务才能同时提交或回滚,多线程场景下,拿到的数据库连接是不一样的
解决:

  • 分布式事务保证
  • 自己实现事务回滚

6、同时使用@Transactional和@Async

A类事务方法调用B类异步方法

public class A{
@Transactional
public void add() {
KsA ksA = new KsA();
ksA.setName("forlan");
ksAService.insert(ksA);
}
} public class B{
@Async
public void insert(KsA ksA) {
this.ksADao.insert(ksA);
int res = 1 / 0;
}
}

原因:同多线程调用问题类似,异步方法属于开启一个新线程执行了
解决:

  • 异步方法加上@Transactional

7、错误使用事务传播行为

具体可以了解 Spring事务传播行为实战

比如:使用了@Transactional(propagation = Propagation.NOT_SUPPORTED),(不支持事务)如果当前存在事务,就把当前事务挂起

8、使用的数据库不支持事务

比如,MySQL中的MyISAM,是不支持事务的
原因:Spring事务基于数据库事务实现

9、是否开启事务支持

我们使用的SpringBoot默认开启事务支持了,通过我们引入的依赖jar包,可以发现@EnableTransactionManagement

Spring事务失效原因分析解决的更多相关文章

  1. spring事务失效情况分析

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt113 <!--[if !supportLists]-->一.&l ...

  2. Spring事务失效的原因

    http://blog.csdn.net/paincupid/article/details/51822599 Spring事务失效的原因 5种大的原因 如使用mysql且引擎是MyISAM,则事务会 ...

  3. Spring事务失效的2种情况

    使用默认的事务处理方式 因为在java的设计中,它认为不继承RuntimeException的异常是”checkException”或普通异常,如IOException,这些异常在java语法中是要求 ...

  4. java面试记录二:spring加载流程、springmvc请求流程、spring事务失效、synchronized和volatile、JMM和JVM模型、二分查找的实现、垃圾收集器、控制台顺序打印ABC的三种线程实现

    注:部分答案引用网络文章 简答题 1.Spring项目启动后的加载流程 (1)使用spring框架的web项目,在tomcat下,是根据web.xml来启动的.web.xml中负责配置启动spring ...

  5. 8个Spring事务失效的场景,你碰到过几种?

    前言 作为Java开发工程师,相信大家对Spring种事务的使用并不陌生.但是你可能只是停留在基础的使用层面上,在遇到一些比较特殊的场景,事务可能没有生效,直接在生产上暴露了,这可能就会导致比较严重的 ...

  6. oracle 索引失效原因及解决方法

    oracle 索引失效原因及解决方法 2010年11月26日 星期五 17:10 一.以下的方法会引起索引失效 ‍1,<>2,单独的>,<,(有时会用到,有时不会)3,like ...

  7. kubectl get 后按2次tab键命令补全的失效原因分析

    kubectl get 后按2次tab键命令补全的失效原因分析 2019/10/28 Chenxin a.bash客户端工具 在centos用户下, cd ~;echo "source &l ...

  8. Spring事务管理全面分析

    Spring 事务属性分析什么是事物  事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常 ...

  9. [心得体会]spring事务源码分析

    spring事务源码分析 1. 事务的初始化注册(从 @EnableTransactionManagement 开始) @Import(TransactionManagementConfigurati ...

  10. Spring事务深入剖析--spring事务失效的原因

    之前我们讲的分布式事务的调用都是在一个service中的事务方法,去调用另外一个service中的业务方法, 如果在一个sevice中存在两个分布式事务方法,在一个seivice中两个事务方法相互嵌套 ...

随机推荐

  1. DHorse系列文章之镜像制作

    DHorse系列文章之镜像制作 制作镜像常用的工具 使用Docker制作镜像 1.使用docker commit制作 该命令使用比较简单,可以自行网上搜索教程. 2.使用Dockerfile制作 这种 ...

  2. 1759D(数位变0)

    题目链接 题目大意: 给你两个整数n, m.你需要求一个数,它满足如下条件: 是n的整数倍,且倍数小于m. 你应该使其末尾的0尽可能的多(如100后面有2个零,1020后面有一个零,我们应该输出100 ...

  3. 第三方模块的下载与使用、requests模块、爬取链家二手房数据、openpyxl模块、hashlib加密模块

    目录 第三方模块的下载与使用 下载第三方模块可能会出现的问题 网络爬虫模块之requests模块 网络爬虫实战之爬取链家二手房数据 自动化办公领域之openpyxl模块 第三方模块的下载与使用 第三方 ...

  4. 第2-4-4章 规则引擎Drools规则属性-业务规则管理系统-组件化-中台

    目录 5. 规则属性 5.1 enabled属性 5.2 dialect属性 5.3 salience属性 5.4 no-loop属性 5.5 activation-group属性 5.6 agend ...

  5. 本地JS文件批量压缩

    最近在维护一个小后台项目,有段JS需要压缩上传到CDN存储服务器.由于之前压缩的JS文件都比较少,都是手动压缩的.这次需要压缩的文件比较多,所以用了批量压缩.特此记录一下,方便大家和自己以后再用到的时 ...

  6. beanshell报错:Error invoking bsh method: eval解决办法(beanshell 不支持Java中的泛型)

    起因:在beanshell中读取CSV文件中的内容,相同的代码在IDEA中可以执行通过,但是在beanshell中报错: ERROR o.a.j.u.BeanShellInterpreter: Err ...

  7. 《MySQL必知必会》知识汇总一

    一.使用MYSQL 展示所有数据库 show databases; 选择数据库 use crashcourse; 展示该数据库中所有的表 show tables; 还可以展示表列的shema约束 sh ...

  8. 【Shell案例】【for循环、seq生成】3、输出7的倍数

    描述写一个 bash脚本以输出数字 0 到 500 中 7 的倍数(0 7 14 21...)的命令 方法1:in方式循环 [if的括号是中括号,中间的条件要有空格] [循环体用do和done配对] ...

  9. vue项目封装 axios 和 api

    一,utils文件夹下新建一个request.js文件 import axios from 'axios'; import QS from 'qs'; import { Toast } from 'v ...

  10. 新款 c++ web framework 支持orm http/2

    c++ web framework很少, 随着c++ 热度升温,c++ 在人工智能 自然语言处理 加快应用. 最近一款国产 c++ web framework 问世 写业务速度跟脚步语言一样速度 自带 ...