首页 > 其他分享 >事务Transactional失效的这10个场景,你一定得知道!

事务Transactional失效的这10个场景,你一定得知道!

时间:2024-01-15 20:32:01浏览次数:27  
标签:10 事务 调用 Transactional 回滚 addOrder 失效 方法

@Transactional失效的场景都有哪些呢?

如图所示!

事务Transactional失效的这10个场景,你一定得知道!_事务

事务Transactional失效的这10个场景,你一定得知道!_mysql_02

以上我们列举了10种场景,接下来我们针对不同的场景来具体的分析下。

一、代理不生效导致

1、同一个类中,方法内部调用事务失效

同一个类中,addOrder()方法无事务,addOrder2()方法存在事务,addOrder()调用addOrder2()。

事务Transactional失效的这10个场景,你一定得知道!_spring_03

我们通过外部方法调用addOrder()方法,来完成数据库的插入,通过手动的设置异常order/0,来观察addOrder2()方法中的数据是否会正常回滚。

事务Transactional失效的这10个场景,你一定得知道!_事务_04

通过数据库的结果显示,数据正常入库了,证明了我们的事务并未生效。

同一个类中,addOrder()和addOrder2()都存在事务,addOrder()调用addOrder2()。

事务Transactional失效的这10个场景,你一定得知道!_mysql_05

order/0 产生异常之后,通过数据库的结果显示,发现数据并未入库,说明事务生效了。

我们发现并不是所有同一个类,方法的内部调用事务都会失效。

那我们就来了解一下事务为啥不生效?

事务Transactional失效的这10个场景,你一定得知道!_mysql_06

看图 !外部代码调用addOrder()方法时,并没有直接进入目标方法,而是首先进入了DynamicAdvisedInterceptor的intercept()方法中。

这是因为我们的orderService的bean在项目在项目启动的时候就生成一个代理对象,这里调用addOrder()方法的,其实是代理对象,而代理对象对目标方法的调用,会转发进入CGLIB动态代理类的intercept()方法中进行增强。

事务Transactional失效的这10个场景,你一定得知道!_回滚_07

在方法调用栈中,我们发现了TransactionInterceptor事务拦截器。

而通过TransactionInterceptor 这个机制,我们完成了对目标方法的增强,例如事务控制,主要处理逻辑在TransactionAspectSupport.invokeWithinTransation()中。

事务Transactional失效的这10个场景,你一定得知道!_spring事务_08

只有当调用addOrder2()方法是通过代理类进行的时候,才能触发事务的拦截。

2、事务方法被final、static修饰

示例代码:

事务Transactional失效的这10个场景,你一定得知道!_spring_09

失效原因:CGLIB是通过生成目标类子类的方式生成代理类的,被final、static修饰的方法,无法被子类重写。

3、当前类没有被Spring管理

例如:Service类中没有@Service注解

public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;
    @Transactional
    public int addOrder(Double amount, String address) {
        int order = orderMapper.addOrder(amount, address);
        int i = order / 0;
        return order;
    }
}

从以上的两种场景分析,我们得知@Transactional事务生效的前提条件是需要代理类对目标方法的调用,才能触发事务处理,如果我们的类没有@Service注解,就不会交给spring容器初始化处理,也就无法为目标类生成代理类。

二、框架或者底层不支持

4、非public修饰的方法(存在版本差异)

示例代码:

事务Transactional失效的这10个场景,你一定得知道!_回滚_10

通过外部接口的调用,异常之后,发现事务正常回滚,数据库数据并没有入库,说明事务是生效的。


springframework的版本:6.0.11


不是说非public修饰的方法,事务不生效吗?

通过本地debug分析源码得知,在spring版本6.0.11中是支持proected修饰的方法的。

事务Transactional失效的这10个场景,你一定得知道!_mysql_11

事务Transactional失效的这10个场景,你一定得知道!_spring事务_12

事务Transactional失效的这10个场景,你一定得知道!_spring_13

对比了spring5.3.25的版本,发现之前的版本,publicMethodOnly默认值确实为true。

事务Transactional失效的这10个场景,你一定得知道!_事务_14

事务Transactional失效的这10个场景,你一定得知道!_mysql_15

事务Transactional失效的这10个场景,你一定得知道!_spring事务_16

事务Transactional失效的这10个场景,你一定得知道!_spring_17

5、事务多线程调用

示例代码:

事务Transactional失效的这10个场景,你一定得知道!_mysql_18

事务Transactional失效的这10个场景,你一定得知道!_回滚_19

当我们使用外部接口调用addOrder()方法时,sysUserService.saveUser()方法发生异常。但是发现orderMapper.addOrder()的数据正常入库了,事务失效。

事务Transactional失效的这10个场景,你一定得知道!_事务_20

通过本地debug和分析源码得知,我们的事务是给线程绑定的(TransactionAspectSupport.prepareTransactionInfo())。

事务Transactional失效的这10个场景,你一定得知道!_spring_21

在执行sysUserService.saveUser()目标方法的时候,我们通过代理类执行逻辑,获取到的事务AbstractPlatformTransactionManager.getTransaction()其实是重新创建的一个事务。

事务Transactional失效的这10个场景,你一定得知道!_回滚_22

因此当saveUser()方法发生异常时,addOrder()方法的事务未能同步回滚数据。

6、数据库本身不支持事务

事务Transactional失效的这10个场景,你一定得知道!_spring_23


事务Transactional失效的这10个场景,你一定得知道!_spring事务_24

三、开发使用不当引发

7、异常被方法内部try catch捕获,没有重新抛出

示例代码:

事务Transactional失效的这10个场景,你一定得知道!_事务_25

当外部接口调用addOrder()方法,异常发生的时候,数据库数据正常入库了,事务未生效。

事务Transactional失效的这10个场景,你一定得知道!_spring事务_26

在TransactionAspectSupport.invokeWithinTransaction()方法中,我们可以看到以下逻辑。

事务Transactional失效的这10个场景,你一定得知道!_事务_27


事务Transactional失效的这10个场景,你一定得知道!_spring事务_28

8、嵌套事务回滚多了

示例代码:

事务Transactional失效的这10个场景,你一定得知道!_事务_29


事务Transactional失效的这10个场景,你一定得知道!_mysql_30

9、rollbackFor属性设置错误

示例代码:

@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;


    @Transactional
    public int addOrder(Double amount, String address) throws FileNotFoundException {
        int order = orderMapper.addOrder(amount, address);
        throw new FileNotFoundException("11111");
    }
}

在demo中,我们手动的抛出FileNotFountException异常,这是一个IOException异常。

当我们使用@Transactional,在未对rollbackFor做配置的情况下,默认是支持对Runtime和Error异常的回滚的。

事务Transactional失效的这10个场景,你一定得知道!_回滚_31

但当我们的demo中的异常是IOException的时候

事务Transactional失效的这10个场景,你一定得知道!_回滚_32

事务Transactional失效的这10个场景,你一定得知道!_回滚_33

从源码694行else逻辑的注释上我们也能看出,无法回滚异常。

所以通常情况下,我们建议指定@Transactional(rollbackFor = Exception.class)的方式进行异常捕获。

10、设置不支持事务的传播机制

Spring支持了7种传播机制,分别为:

事务Transactional失效的这10个场景,你一定得知道!_mysql_34

上面不支持事务的传播机制为:PROPAGATION_SUPPORTS,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER。

如果配置了这三种传播方式的话,在发生异常的时候,事务是不会回滚的。

示例代码:

@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;


    @Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS)
    public int addOrder(Double amount, String address) throws FileNotFoundException {
        int order = orderMapper.addOrder(amount, address);
        throw new FileNotFoundException("11111");
    }
}


事务Transactional失效的这10个场景,你一定得知道!_mysql_35

在处理事务异常回滚AbstractPlatformTransactionManager.processRollback()的逻辑中,这三种传播机制,就只是打印了下debug日志,没有进行真正的回滚,从日志记录信息中我们可以看到:


logger.debug("Should roll back transaction but cannot - no transaction available");


应该回滚但是不能,因为没有可用的事务。

最后说一句(求关注!别白嫖!)

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

标签:10,事务,调用,Transactional,回滚,addOrder,失效,方法
From: https://blog.51cto.com/u_16502039/9258095

相关文章

  • 紫光展锐T610安卓核心板_虎贲T610安卓核心板性能参数
    紫光展锐T610核心板是一款紧凑结构设计的智能模块,尺寸标准为52.5MM38.5MM2.9mm,适合对产品结构尺寸要求更高的场景。核心板搭载Android11操作系统,采用12nm制程工艺,拥有八核1.8GHZ的处理器,由[email protected][email protected]构成,内存为6GB+128GB。此外,还配备了强大的ARMMali......
  • width:100%与width:auto区别
    小知识width:100%与width:auto区别width:100%:子元素的content撑满父元素的content,如果子元素还有padding、border等属性,或者是在父元素上设置了边距和填充,都有可能会造成子元素区域溢出显示;width:auto:是子元素的content+padding+border+margin等撑满父元素的cont......
  • 5G穿墙王!TP-LINK发布BE5100 Wi-Fi 7路由器:2.5G网口 279元
    1月14日消息,日前,TP-LINK发布BE5100Wi-Fi7路由器,到手价279元,支持MLO、4KQAM、MRU、前导打孔等Wi-Fi7新特性。据介绍,在MLO多链路技术加持下,2.4G+5G叠加快至7.3倍,4KQAM高阶调制,速率提升至120%。MRU技术允许将多个资源块分配给单个用户,提升传输效率,降低延迟。TP-LINKBE5100......
  • abc101d<打表,数学>
    题目D-SnukeNumbers思路打表找规律:voidbf(intn){vector<int>ans;doubleminn=double(n)/get(n);for(inti=n-1;i>=1;i--){doublet=double(i)/get(i);if(t<=minn+1e-9){m......
  • 2023年最新!window10于VMware安装教程
    2023年最新!window10于VMware安装教程导航目录2023年最新!window10于VMware安装教程导航一、下载ISO镜像文件二、VMware进行配置三、启动并配置虚拟机一、下载ISO镜像文件自行在网上搜寻想要下载的版本,我这提供MSDN的下载链接:https://www.xitongku.com/,纯净无广告二、VMw......
  • abc100d<枚举>
    题目D-PatisserieABC思路枚举三组权重和的正负情况,一共2^3种可能;对于每种情况,直接计算对应得分,取最大的m个蛋糕的得分求和;对所有情况的得分取最大即可。总结代码点击查看代码#include<iostream>#include<algorithm>#include<vector>usingnamespacestd;usi......
  • 梦回2004!我用全志V3s做了个成本100元,功能媲美MP4的随身终端
    本项目是基于全志V3S的随身终端(类似MP4),命名为V3S-PI,开发板使用四层板制作,全板采用0603电容电阻,相较于0402,制作更为方便,同时成本可压缩至100以内。项目简介开发板选用全志V3S为主控,V3s单核Cortex-A7带有硬件浮点计算,且芯片内封64MbyteDDR2,无需再外接DDR2芯片,极大程度上为开发板的走......
  • 沸点密封科技(江苏)有限公司选购我司HS-DSC-101B差示扫描量热仪
    近日,沸点密封科技(江苏)有限公司经过严谨的市场调研和设备比对,最终选择从我司购置一台HS-DSC-101B差示扫描量热仪。这一决策不仅彰显了沸点密封科技对于产品质量的极致追求,也标志着我司科技设备可靠性得到了行业的广泛认可。沸点密封科技(江苏)有限公司HS-DSC-101B差示扫描量热仪作为我......
  • WIN10系统彻底永久关闭自动更新
    一、首先我们需要做的就是禁用WindowsUpdate服务1、通过键盘Win+R健,弹出运行对话框,输入命令 services.msc ,按“确定”按钮,即可打开服务弹窗。 2、往下拉,寻找到找到WindowsUpdate,双击打开。 3、双击打开弹框,点击“停止”,将启动类型选为“禁用”,最后点击确定。 4、......
  • Windows10安装Docker
    一、安装DockerDesktopforWindows在官网下载DockerDesktopforWindows:https://docs.docker.com/desktop/install/windows-install/;双击下载的DockerforWindowsInstaller安装文件,一路Next,点击Finish完成安装。注意:保持默认选择“InstallrequiredWindowscompo......