Spring事务失效常见的八种场景
admin
2024-02-04 06:11:35
0

文章目录

    • 1. 方法自调用
    • 2. 方法修饰符为private
    • 3. 方法是final的
    • 4. 单独的线程调用
    • 5. Spring中没加@Configuration注解
    • 6. 异常被吃掉
    • 7. 类没有被Spring管理
    • 8. 数据库没有开启事物

1. 方法自调用

第一类,@Transactional注解未生效情况,其实这种并不是事物失效,仅仅是注解失效,注解写了更没写一样

解决方案:

  • 将被调用的方法拆到单独的bean中,让切面起作用
  • 自己注入自己获取代理类
  • @EnableAspectJAutoProxy(exposeProxy = true) + UserService userService = (UserService) AopContext.currentProxy();

Spring事务是基于AOP的,只有当代理对象调用某个方法时,Spring的事务才会生效,而在一个方法中调用this.xxx()方法时,由于this并不是代理对象,所以会导致事务失效

@Transactional
public void a(){jdbcTemplate.execute("insert into t1 values(1)");throw new RuntimeException();
}// 自调用
public void b(){// 由于调用者并不是代理对象,所以切面失败导致事物失效a();
}

还有一种情况

// 此时相当于`a`方法上面根本就没贴事物注解一样
@Transactional(propagation = Propagation.NEVER)
public void a(){jdbcTemplate.execute("insert into t1 values(1)");throw new RuntimeException();
}// 调用方法也加了事物注解,此时会进行回滚,但是是由b方法的事物就行回滚的
@Transactional
public void b(){// 由于调用者并不是代理对象,所以切面失败导致事物失效a();
}

所以解决方案就是用代理对象调用即可

public class UserService {@Autowired // 自己注入自己private UserService userService;@Transactionalpublic void a(){jdbcTemplate.execute("insert into t1 values(1)");throw new RuntimeException();}// 事物生效public void b(){userService.a();}
}

或者可以通过代理上下文获取当前类的代理对象,但是这种需要我们在配置类上面设置属性@EnableAspectJAutoProxy(exposeProxy = true)

public class UserService {@Transactionalpublic void a(){jdbcTemplate.execute("insert into t1 values(1)");throw new RuntimeException();}// 事物生效public void b(){// 获取当前类的代理对象UserService userService = (UserService) AopContext.currentProxy();userService.a();}
}

2. 方法修饰符为private

  • cglib代理是基于父子类的,如果方法私有无法在子类中获取到,无法重写,只能执行父类的方法,但是父类中没有jdbcTemplate,会抛出NPE
  • 多态口诀:new谁调用谁的方法,谁创建使用谁的属性
public class UserService {// cglib代理是基于父子类的,如果方法私有无法在子类中获取到,只能执行父类的方法,但是父类中没有`jdbcTemplate`,`NPE`@Transactionalprivate void a(){jdbcTemplate.execute("insert into t1 values(1)");throw new RuntimeException();}
}

3. 方法是final的

同上,代理类无法重写代理的方法

4. 单独的线程调用

Mybatis或者JdbcTemplate执行SQL时,会从ThreadLocal中去获取数据库连接对象,如果开启事物的线程和执行SQL的线程不是同一个线程,就拿不到数据库连接对象,这样,Mybatis或者JdbcTemplate就会重新创建一个数据库连接用来执行SQL,如果这个事物自动事物提交autocommit默认开启的话,就不会因为异常而进行回滚

public class UserService {// 事物失效@Transactionalprivate void a(){new Thread(() -> {jdbcTemplate.execute("insert into t1 values(1)");throw new RuntimeException();}).start();}
}

5. Spring中没加@Configuration注解

在Spring中,由于MybatisJdbcTemplate会从ThreadLocal中获取数据库连接,但是ThreadLocal里面存的是map,即ThreadLocal>的结构

如果没有添加@Configuration注解,会导致Map中存的DateSource和MybatisJdbcTemplate对象不相等,从而拿不到数据库连接,导致自己会新建一个,从而导致事物失效

注意:在SpringBoot中由于自动装箱,不会出现这种问题

6. 异常被吃掉

Spring默认只会对RuntimeExceptionError进行回滚

7. 类没有被Spring管理

8. 数据库没有开启事物

相关内容

热门资讯

华泰证券:消费新格局下的赛事经... 来源:华泰睿思 核心观点 2026年是“十五五”开局之年,促进服务业消费是今年较为清晰的一条政策主线...
土耳其主要银行业指数上涨3% 每经AI快讯,5月7日,土耳其主要银行业指数上涨3%。 每日经济新闻
食品饮料分化,岂是业绩这么简单... 本篇为大家准备了5条要闻,涵盖行业、新股、海外市场等多个维度,方便大家快速get核心信息。一、要闻导...
550 亿美元!马斯克的「芯片... 当最大的 AI 算力消费者决定自己建芯片厂,这件事的意义已经超出了商业范畴。 作者|桦林舞王 编辑|...
央行连续第18个月增持黄金 据央行官网披露的最新数据,中国4月末黄金储备报7464万盎司,环比增加26万盎司,3月末为7438万...
腾讯等入股机器人灵巧手研发商临... 天眼查App显示,近日,上海临界点创新智能科技有限公司发生工商变更,新增腾讯旗下上海启善投资有限公司...
云计算指数连续上涨,关注低费率... 5月7日,科技赛道延续涨势。截至收盘,中证云计算与大数据主题指数上涨2.6%,已连续4个交易日上涨,...
寒武纪股价再成A股最贵,半导体... 一方面,受益于AI产业发展,不少半导体公司业绩上涨;另一方面,美股半导体的上涨也带动了A股行情 文|...
原创 马... 据5月7日报道,全球商业航天巨头SpaceX的上市计划终于揭开了神秘面纱。 然而,这份披露的IPO注...
光纤、CPO等方向领涨,创业板... 5月7日,算力硬件股受益于AI浪潮继续走强,光纤、CPO、PCB方向领涨,截至收盘,创业板成长指数上...
马斯克解散xAI,联手Anth... 5月7日,据外媒报道,埃隆·马斯克在社交平台上表示,xAI作为一家独立公司将被解散,未来只有Spac...
节后开门红!A股成交站上3万亿... 2026年5月6日,“五一”假期后首个交易日,A股市场迎来开门红。主要股指全线高开高走,科技成长板块...
两大国资股东拟清仓,底价约20... 图源:图虫创意 近日,北京产权交易所于近日披露了光大永明人寿保险有限公司(下称“光大永明人寿”)两笔...
智慧医院人员定位系统定制服务|... 医疗行业的挑战与智慧化转型 当前,医疗行业在管理与服务上面临诸多挑战。在效率方面,医护人员调度低效、...
礼来启动投资级债券发行 为收购... 5月6日消息,礼来(LLY.US)已启动投资级债券发行,以为其近期一系列收购交易筹集资金。据知情人士...
央行,连续18个月增持黄金! 【导读】4月外储规模环比上升2.05%,央行连续18个月增持黄金 中国基金报记者 张玲 5月7日,国...
原创 2... 一套房子值400万,每年还在贬值;一套房子月租只要3000块,住得还不错。这笔账,搁几年前没人敢算,...
原创 特... 特朗普大概做梦也没想到,自己有一天会被"制造业"三个字折腾得夜不能寐。从竞选到执政,他嘴里翻来覆去念...
“钴业大王”陈雪华再赌资源周期... 图片来源:图虫创意 “钴业大王”陈雪华再出手,拟超14亿元布局非洲锂矿。 5月7日上午,华友钴业(6...