一、前言

开发中我们经常使用 @Transactional注解来启用Spring事务管理,但是如果使用方法不当,会遇到注解不生效该事务回滚的地方却没有回滚的问题。

总结下一般是以下几个原因:

  1. @Transactional 注解只能应用到 public 可见度的方法上。 如果应用在protected、private或者 package可见度的方法上,也不会报错,不过事务设置不会起作用。
  2. 默认情况下,spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。针对这种情况,可以try catch checked异常后进行手动事务回滚。
  3. 数据库引擎要支持事务,如果是mysql,注意表要使用支持事务的引擎,比如InnoDB,如果是MyISAM,事务是不起作用的。
  4. 同一个类中, 一个no-transactional的方法去调用transactional的方法, 事务会失效。

本文主要讲第四种情况如何处理。

二、示例

事务失效示例1

事务失效示例2

执行add() 方法后数据库插入了两条数据,也就说明以上两段代码中,doAdd()方法的事务增强都不会执行,具体原因可以参考这篇文章

那么如果想让doAdd()方法在发生异常时数据库事务回滚,有什么解决办法吗?

第一步开启配置expose-proxy

如果使用的xml配置文件的方式,则添加如下内容:

<aop:aspectj-autoproxy  expose-proxy="true"  />

如果用的SpringBoot框架,则直接在启动类上添加如下注解即可。

@EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)

第二步修改代码

将原来的调用代码this.doAdd(person); 改为 ((PersonService)AopContext.currentProxy()).doAdd(person);

enter description here

再进行测试发现数据库只插入了一条数据(person2),说明doAdd() 方法里的事务增强生效了。

三、源码分析

点进 @EnableAspectJAutoProxy 注解代码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false; }

发现它注入了一个Bean AspectJAutoProxyRegistrar,再看看这个AspectJAutoProxyRegistrar是什么。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 解析注解EnableAspectJAutoProxy
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
// 如果设置了exposeProxy=true就强制使用
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
} }

AopConfigUtils#forceAutoProxyCreatorToExposeProxy

// 强制使用的过程其实也是一个属性设置的过程
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
} /**
* The bean name of the internally managed auto-proxy creator.
*/
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";

@Transactional注解失效的解决方案的更多相关文章

  1. @Transactional 注解失效场景

    @Transactional可以用在接口.类.类方法上. 作用于类:当把@Transactional注解放在类上时,表示该类的所有public方法都配置了该事物注解. 作用于方法:表示该方法配置了事物 ...

  2. @Transactional注解失效

    一.特性 先来了解一下@Transactional注解事务的特性吧,可以更好排查问题 1.service类标签(一般不建议在接口上)上添加@Transactional,可以将整个类纳入spring事务 ...

  3. 一口气说出 6种,@Transactional注解的失效场景

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一口气说出 9种 分布式ID生成方式,面试官有点懵了 面试总被问 ...

  4. @Transactional注解的失效场景

    一口气说出 6种,@Transactional注解的失效场景 计算机java编程 发布时间: 20-03-1912:35优质科技领域创作者 引言 昨天公众号粉丝咨询了一个问题,说自己之前面试被问@Tr ...

  5. spring事务注解失效问题

    问题描述: 由于工作需要,需要在spring中配置两个数据源,有一天突然发现@Transactional注解失效 环境框架: springmvc+spring+spring jdbcTemplate ...

  6. Spring aop注解失效

    问题 在spring 中使用 @Transactional . @Cacheable 或 自定义 AOP 注解时,对象内部方法中调用该对象的其他使用aop机制的方法会失效. @Transactiona ...

  7. Spring @Transactional注解不起作用解决办法及原理分析

    Transactional失效场景介绍 第一种 Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用.例如以下代码. 定义一个错误的@Trans ...

  8. Spring中@Translational注解失效场景

    今天面试被问到@Translational注解什么场景下失效,我一脸懵逼,说的恍恍惚惚的,下来我就总结一下@Translational注解失效的场景! @Transactional 注解相信大家并不陌 ...

  9. @Transaction注解失效的几种场景

    一.@Transactional介绍 1.@Transactional注解可以作用于哪些地方? @Transactional 可以作用在接口.类.类方法上. 作用于类:表示所有该类的public方法都 ...

随机推荐

  1. 异步任务-----django-celery

    异步任务 ---- django-celery   大家的知道celery的使用,网上也有很多的教程.因为最近在使用django来完成项目,无意间发现发现有个东西叫django-celery,比cel ...

  2. Python使用import导入模块时报ValueError: source code string cannot contain null bytes的解决方案

    老猿在导入一个Python模块时报错: >>> import restartnet.py Traceback (most recent call last): File " ...

  3. uniapp 微信授权登陆

    准备工作: 1.微信开发者账号 2.AppId .AppSecret (这些可以在开放平台申请到) 第一步 添加移动应用,仔细添加上述信息: 审批通过后,即刻 第二步 打开uniapp,开启OAuth ...

  4. Newbe.ObjectVisitor 0.4.4 发布,模型验证器上线

    Newbe.Claptrap 0.4.4 发布,模型验证器上线. 更新内容 完全基于表达式树的模型验证器 本版本,我们带来了基于表达式树实现的模型验证器.并实现了很多内置的验证方法. 我们罗列了与 F ...

  5. justify-content属性详解

    justify-content 定义了flexbox flexbox内的元素在主轴的方向上的对齐方式. 它可以设置以下几种对齐方式: 靠近一方 justify-content:center: /*fl ...

  6. 题解-CF1389F Bicolored Segments

    题面 CF1389F Bicolored Segments 给 \(n\) 条线段 \([l_i,r_i]\),每条有个颜色 \(t_i\in\{0,1\}\),求最多选出多少条线段,使没有不同颜色的 ...

  7. Python 中的哈希表

    Python 中的哈希表:对字典的理解   有没有想过,Python中的字典为什么这么高效稳定.原因是他是建立在hash表上.了解Python中的hash表有助于更好的理解Python,因为Pytho ...

  8. 《图解TCP/IP》笔记

    OSI参考模型 协议分层 为什么需要分层? 简化网络协议. 每一层只需要衔接上下层的服务. 利于模块化开发. 解耦. 分层的问题 过分模块化.提高数据处理的开销. OSI参考模型 作用及意义 将复杂的 ...

  9. do{}while(false)的用法

    do{}while(false): 在工作中我们能经常发现有人写 do{}while(false)  这样的代码,初看时让人迷惑不解,按照上面的语法 do{}while(false) 这样 do{} ...

  10. DarkMode(1):产品应用深色模式分析

    为什么Dark Mode变得越来越流行 2018 年的 macOS Mojave 率先支持了深色外观,紧接着 Windows 10 在 2018 年的 10 月份大版本更新中,也引入了 Dark Mo ...