springboot异步线程事务丢失

1.解决方法,使用事务将连接注入到另一个线程中

声明式事务底层原理

DataSourceTransactionManager

源码在这个类中

 这个方法里

datasource 数据源获取的连接 

关闭事务自动提交 来开启事务

 通

### Spring Boot事务注解 `@Transactional` 失效的场景、原因及解决方案 #### 一、失效场景分析 1. **未通过代理调用方法** 当使用 `@Transactional` 注解的方法被同一类中的其他方法直接调用时,事务并不会生效。这是因为在 Spring 中,`@Transactional` 是基于动态代理实现的,只有外部对象通过代理调用来触发该方法时,事务才会起作用[^2]。 2. **异常类型不匹配** 默认情况下,Spring事务只会在遇到 `RuntimeException` 或其子类时才回滚。如果抛出的是受检异常(Checked Exception),则不会触发事务回滚,除非显式配置了 `rollbackFor` 参数[^1]。 3. **传播行为配置不当** 如果事务的传播行为设置不合理,也可能导致事务失效。例如,当传播行为设为 `PROPAGATION_SUPPORTS` 时,如果没有现有事务,则当前操作将不在事务中执行。 4. **数据库引擎不支持事务** 数据库本身如果不支持事务功能(如 MySQL 的 MyISAM 存储引擎),即使应用层配置了事务,也无法正常工作。因此,应确保使用的存储引擎支持事务,比如 MySQL 的 InnoDB。 5. **异步方法中使用事务** 在同一个方法上同时标注 `@Async` 和 `@Transactional` 导致事务失效的情况较为特殊。原因是 `@Async` 方法会被分配到一个新的线程去执行,而默认情况下,Spring事务上下文仅适用于创建它的原始线程[^4]。 --- #### 二、具体原因解析 - **代理机制限制** Spring 使用 AOP 动态代理技术来拦截带有 `@Transactional` 注解的方法调用,并为其提供事务管理服务。但如果方法是从内部调用而非经过代理对象访问,则无法激活事务逻辑[^2]。 - **异常捕获问题** 若在业务代码中手动捕获并吞掉了所有异常,那么即便设置了事务也不会发生回滚动作,因为框架检测不到任何错误信号[^1]。 - **线程切换影响** 当涉及多线程编程时(例如结合 `@Async` 使用),原生主线程上的事务状态难以传递至新启动的工作线程里,从而造成事务丢失现象[^4]。 --- #### 三、解决方案总结 针对以上提到的各种可能导致 `@Transactional` 注解失效的情形,分别给出如下应对措施: 1. **调整方法调用方式** 确保标记有 `@Transactional` 的方法始终是由外部组件间接调用而不是简单地自我循环引用;必要时可通过引入额外的服务层封装公共逻辑以便正确触发动态代理过程[^2]。 2. **修改回滚策略** 自定义 `@Transactional` 注解参数以覆盖默认行为,允许特定条件下对任意类型的异常均实施回滚处理。例如: ```java @Transactional(rollbackFor = {Exception.class}) ``` 3. **优化事务传播模式** 根据实际需求重新评估每处需开启事务的位置是否有必要更改现有的传播级别设定,避免不必要的嵌套或独立运行状况出现意外后果。 4. **选用合适的数据库驱动与表结构设计** 定期审查生产环境下的数据持久化设施选型情况,确认它们都已启用完整的ACID特性保障能力后再部署上线应用程序[^2]。 5. **分离异步任务与事务边界** 不要在单个函数体内混合声明 `@Async` 和 `@Transactional` 。而是考虑重构代码架构让两者各自单独承担职责范围内的责任领域分开运作[^4]。 --- ### 示例代码展示 下面是一组改进后的样例演示如何规避常见的陷阱: ```java @Service public class OrderService { @Autowired private PaymentService paymentService; /** * 正确做法:通过另一个 Service 类调用带事务的方法 */ public void placeOrder(Long orderId) { try { this.paymentService.charge(orderId); } catch (PaymentFailedException e) { log.error("支付失败", e); throw new TransactionRollbackException(e.getMessage(), e); } } } @Service public class PaymentService { @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void charge(Long orderId) throws PaymentFailedException { // 执行扣款逻辑... if (!isSuccessful()) { throw new PaymentFailedException("模拟支付失败"); } } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值