@Transactional是我们在用Spring时候几乎逃不掉的一个注解,该注解主要用来声明事务。它的实现原理是通过Spring AOP在注解修饰方法的前后织入事务管理的实现语句,所以开发者只需要通过一个注解就能代替一系列繁琐的事务开始、事务关闭等重复性的编码任务。

编码方式确实简单了,但也因为隐藏了直观的实现逻辑,一些错误的编码方法可能会让@Transactional注解失效,达不到事务的作用。最直接的表现就是:方法执行过程中抛出了异常,但事务没有回滚,最终导致了脏数据的产生。

之前我在博客上也写过一篇有趣的讨论我来出个题:这个事务会不会回滚?,当时很多人都给出了标准的错误答案,如果没看过的小伙伴不妨进去挑战一下?

虽然之前讨论了一些特殊情况,但还是一直有小伙伴会邮件、微信群里问一些关于事务失效的问题。主要还是@Transactional声明事务失效的情况真的是多种多样!所以,今天写一篇总结一下,如果下次再碰到,那就打开这片文章,一个个顺下来看,是不是哪里写错了。当然可能这里还会有遗漏,所以如果你有其他错误案例,也可以告诉我,我会持续整理到这篇文章里。

1. 在同一个类中调用

错误案例:

public class A {

    public void methodA() {
methodB(); // 其他操作
} @Transactional
public void methodB() {
// 写数据库操作
} }

这类错误适用于所有基于Spring AOP实现的注解,比如:《使用@Async实现异步调用》中提到的@Async注解,《使用@Scheduled实现定时任务》中提到的@Scheduled注解,还有Spring缓存注解的使用解中提到的@Cacheable注解等。

解决这个问题的方法比较简单,还是合理规划好层次关系即可,比如这样:

@Service
@AllArgsConstructor
public class A { private B b; public void methodA() {
b.methodB();
// 其他操作
}
} @Service
public class B { @Transactional
public void methodB() {
// 写数据库操作
} }

注意:这里A类用了构造器注入B的实现(为什么没用@Autowrire,可以看看前几天分享的这篇什么时候不要用@Autowired注入),构造函数用Lombok的@AllArgsConstructor生成(这个不熟悉的话可以看看之前这篇Lombok:让JAVA代码更优雅)。

2. @Transactional修饰方法不是public

错误案例:

public class TransactionalMistake {

    @Transactional
private void method() {
// 写数据库操作
} }

这也是基于Spring AOP实现的注解所要满足的要求。这个最简单,很好理解,也很直观,就不详细展开了。直接把方法访问类型改成public即可。

3. 不同的数据源

错误案例:

public class TransactionalMistake {

    @Transactional
public void createOrder(Order order) {
orderRepo1.save(order);
orderRepo2.save(order);
} }

有的时候,我们一个操作可能会同时写多个数据源,比如上面这个例子里的orderRepo1和orderRepo2是连接的两个不同数据源。默认情况下,这种跨数据源的事务是不会成功的。

如果要在多个数据源之间实现事务,那么可以引入JTA,具体如何做的话可以看看之前的这篇分享《使用JTA实现多数据源的事务管理》

4. 回滚异常配置不正确

默认情况下,仅对RuntimeException和Error进行回滚。如果不是的它们及它们的子孙异常的话,就不会回滚。

所以,在自定义异常的时候,要做好适当的规划,如果要影响事务回滚,可以定义为RuntimeException的子类;如果不是RuntimeException,但也希望触发回滚,那么可以使用rollbackFor属性来指定要回滚的异常。

public class TransactionalMistake {

    @Transactional(rollbackFor = XXXException.class)
public void method() throws XXXException { } }

5. 数据库引擎不支持事务

这个来源于一个读者反馈的例子,代码跟我的案例一摸一样,我这边是好的,但他就是不回滚。

后来排查出来是因为漏了一个关键属性的配置:

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

这里的spring.jpa.database-platform配置主要用来设置hibernate使用的方言。这里特地采用了MySQL5InnoDBDialect,主要为了保障在使用Spring Data JPA时候,Hibernate自动创建表的时候使用InnoDB存储引擎,不然就会以默认存储引擎MyISAM来建表,而MyISAM存储引擎是没有事务的。

如果你的事务没有生效,那么可以看看创建的表,是不是使用了MyISAM存储引擎,如果是的话,那就是这个原因了!

小结

如果你看到最后,发现还有其他情况还没有囊括其中,欢迎告诉我们哟,我们会持续更新这篇文章!以帮助碰到此类问题的读者。

好了,今天的学习就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的Spring技术交流群,参与交流与讨论,更好的学习与进步!

欢迎关注我的公众号:程序猿DD,分享外面看不到的干货与思考!

使用 @Transactional 时常犯的N种错误的更多相关文章

  1. Java开发者写SQL时常犯的10个错误

        首页 所有文章 资讯 Web 架构 基础技术 书籍 教程 我要投稿 更多频道 » - 导航条 - 首页 所有文章 资讯 Web 架构 基础技术 书籍 教程 我要投稿 更多频道 » - iOS ...

  2. Java 程序员在写 SQL 时常犯的 10 个错误

    Java程序员编程时需要混合面向对象思维和一般命令式编程的方法,能否完美的将两者结合起来完全得依靠编程人员的水准: 技能(任何人都能容易学会命令式编程) 模式(有些人用“模式-模式”,举个例子,模式可 ...

  3. C语言编程时常犯十八个错误

    C语言的最大特点是:功能强.使用方便灵活.C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活给程序的调试带来了许多不便,尤其对初学C语言的人来说,经 ...

  4. 使用 Spring Framework 时常犯的十大错误

    Spring 可以说是最流行的 Java 框架之一,也是一只需要驯服的强大野兽.虽然它的基本概念相当容易掌握,但成为一名强大的 Spring 开发者仍需要很多时间和努力. 在本文中,我们将介绍 Spr ...

  5. 编写Java程序最容易犯的21种错误

    1.duplicated code 代码重复几乎是最常见的异味了.他也是refactoring的主要目标之一.代码重复往往来自于copy-and-paste的编程风格.与他相对应oaoo是一个好系统的 ...

  6. Web开发人员常犯的10个错误

    说到开发一个运行在现代网络中的网站:Web开发人员需要选择虚拟主机平台和底层数据存储,准备编写HTML.CSS和JavaScript用的工具,要有设计执行方式,以及一些可用的JavaScript库/框 ...

  7. Java程序员常犯的10个错误

      本文总结了Java程序员常犯的10个错误. #1. 把Array转化成ArrayList 把Array转化成ArrayList,程序员经常用以下方法: List<String> lis ...

  8. OI中常犯的傻逼错误总结

    OI中常犯的傻逼错误总结 问题 解决方案 文件名出错,包括文件夹,程序文件名,输入输出文件名  复制pdf的名字  没有去掉调试信息  调试时在后面加个显眼的标记  数组开小,超过定义大小,maxn/ ...

  9. Valgrind memcheck 8种错误实例

    调不尽的内存泄漏,用不完的Valgrind Valgrind 安装 1. 到www.valgrind.org下载最新版valgrind-3.2.3.tar.bz2 2. 解压安装包:tar –jxvf ...

随机推荐

  1. 前端规范之CSS规范(Stylelint)

    代码规范是软件开发领域经久不衰的话题,几乎所有工程师在开发过程中都会遇到或思考过这一问题.而随着前端应用的大型化和复杂化,越来越多的前端团队也开始重视代码规范.同样,前段时间,笔者所在的团队也开展了一 ...

  2. Ueditor Version 1.4.3.3 SSRF

    点以前挖的洞.Ueditor是支持获取远程图片,较为经典的进行限制url请求,但是可以通过DNS重绑定绕过其验证. 代码分析 一般请求的url如下,其中source为数组,值为图片地址: /edito ...

  3. 解析csv数据绘制曲线图

    一个解析csv数据的小工具,所做项目中要查看脉冲图谱,经理就让我这个刚入职的小萌新写了个小程序.同事将csv格式的脉冲数据发给我,我的想法就是,将这些csv里的数据作为纵轴,x++为横轴,绘制出折线图 ...

  4. 洛谷4755 Beautiful Pair (分治)

    题目描述 小D有个数列 \(a\),当一个数对 \((i,j)(i\le j)\) 满足\(a_i\)和\(a_j\)的积 不大于 \(a_i \cdots a_j\) 中的最大值时,小D认为这个数对 ...

  5. FastAPI 学习之路(二)

    之前的文章已经介绍了如何安装,以及简单的使用,这篇文章呢,我们就不去分享如何安装对应的包了. 我们如何去编写呢,其实很简单,按照下面的步骤,一个简单的基于fastapi的接口就编写完毕. 首先:创建一 ...

  6. netty系列之:让TLS支持http2

    目录 简介 TLS的扩展协议NPN和ALPN SslProvider ApplicationProtocolConfig 构建SslContext ProtocolNegotiationHandler ...

  7. Vim 不区分大小写

    Vim 不区分大小写 忽略:set ignorecase 恢复:set noignorecase

  8. 经典论文系列 | 缩小Anchor-based和Anchor-free检测之间差距的方法:自适应训练样本选择

    ​  前言  本文介绍一篇CVPR2020的论文,它在paperswithcode上获得了16887星,谷歌学术上有261的引用次数. 论文主要介绍了目标检测现有的研究进展.anchor-based和 ...

  9. Noip模拟49 2021.9.7

    T1 reverse 又一道板子打假的挂分题,直接挂到倒二.. 考场上思路神奇,居然想到用$bfs$建边然后跑最短路, 其实当时也想到了直接$bfs$,但是不知道为啥觉得$dij$屌就没直接打$bfs ...

  10. 2021.7.17 NKOJ周赛总结

    发现自己简直是个智障:T1模数写成1e9+9:T2居然没有考虑刚好一个周期的情况:T4用"%lld"读入"unsigned long long".~qwq~ T ...