Java基础、中级、高级、架构面试资料

从根上理解为什么你的 @Transational 注解失效了

JAVA herman 2873浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog2,发送下载链接帮助你免费下载!
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云

在面试中,很多人可能都会被问到“@Transational 注解失效了,可能原因是什么?”这类问题。

网上有很多答案。比如,@Transational 只能作用在 public 方法上。再比如,在同一个类中,一个 nan-transactional 的方法去调用 transactional 的方法,事务也会失效等。

@Transational 注解失效,你没得选择

其实这个问题,不仅困惑着你们,stackoverflow 上也非常的热门。我总结一下,你可以根据下面的方式进行排查你的代码。

  1. @Transactional 加于private方法,无效
  2. @Transactional 加于未加入接口的public方法, 再通过普通接口方法调用,无效
  3. @Transactional 加于接口方法,无论下面调用的是private或public方法,都有效
  4. @Transactional 加于接口方法后,被本类普通接口方法直接调用,无效
  5. @Transactional 加于接口方法后,被本类普通接口方法通过接口调用,有效
  6. @Transactional 加于接口方法后,被它类的接口方法调用,有效
  7. @Transactional 加于接口方法后,被它类的私有方法调用后,有效

Transactional 是否生效,仅取决于是否加载于接口方法,并且是否通过接口方法调用(而不是本类调用)。

为什么会这样呢?我今天简单的从代理的角度给大家讲一讲。

@Transactional 失效的背后其实就是 Spring 代理机制造成的。说白了,就是通过 Spring 容器获取的类对象,很多情况下并不是原类,而是被 Spring 修饰过了的代理类。然后,你在被代理的方法中调用当前类的其它方法,此时就是调用的原生类中的方法。

听不懂没关系,我下面用伪代码给你演示一下,你就知道了。

假如现在要执行 Xttblog 类对象的方法 invoke(),而用 Spring 代理后,会对 Xttblog 类做修饰,也就是会对 Xttblog 的 test 方法生成一个代理类。

执行,调用代理方法 proxyXttblogbean.invoke():

before 操作
invoke(bean,Xttblog)
after 操作

实际你运行的是 Spring 修饰过的代理类 proxyXttblogbean.invoke()方法。

这样就会造成一个问题,如果你在 invoke() 中调用 Xttblog 类的其余方法 invoke2(),此时 invoke2() 是直接调用的原类的 Xttblog.invoke2(),而不是代理类 proxyXttblogbean.invoke2()。这时 Xttblog.invoke2() 上的一些注解全部都没有被增强修饰。所以,最终的结果就和你的预期不一致了。

从根上知道了发生这类问题的原因,问题就好解决了。比如,我们可以想办法手动拿到代理对象。类似下面的伪代码:

// 在invoke()方法内部调用invoke2()方法
// 1.直接调用invoke2(),注解失效。
invoke2()
// 2.拿到代理类对象,再调用invoke2()。
((Xttblog)AopContext.currentProxy()).invoke2()

至于 private 方法上的注解也失效,原因也很简单。因为 Spring 不管使用的是 JDK 动态代理还是 CGLIB 动态代理,一个是针对实现接口的类,一个是通过子类实现。无论是接口还是父类,显然都不能出现 private 方法,否则子类或实现类都不能覆盖到。

如果方法为 private,那么在代理过程中,根本找不到这个方法,引起代理对象创建出现问题,也导致了有的对象没有注入进去。

五一放假了,祝大家五一快乐!

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » 从根上理解为什么你的 @Transational 注解失效了