Java事务踩坑

文章目录

  • 一.基础
      • 1.1 本地写 + rpc写
      • 1.2 transaction事务注解
  • 二、@Transactional使用注意事项
      • 2.1 踩坑-Methods should not call same-class methods with incompatible "@Transactional" values问题
      • 2.1、事务使用注意事项
      • 2.2、事务失效场景
      • 2.3、踩坑-多数据源,某一数据源未配置事务name,导致事务失效

一.基础

1.1 本地写 + rpc写

本地写事务和rpc写操作(最好)不要放在一个事物中。(除非有重试机制)

因为若本地写事务成功了,rpc写操作timeout执行失败(但是实际上,改rpc操作已经在远程成功了),会导致,本地写操作回滚。造成,本地未写,远程写成功了。

  • 场景1:

1.本地写

2.rpc写

若rpc写失败了,本地成功了。就会导致,不一致。

虽然rpc失败,RuntimeException也抛出来了,并且在最外层也catch住了。这样前端会有错误信息提示。如果用户手动再点一次,就能达到重试的效果,这样,如果本地写幂等了,那么rpc写还有一次重新执行的机会。但是如果用户一看报错了,很蒙圈,直接溜了,不操作了。那么此时就会出现本地数据和远端数据不一致的情况。

  • 场景2:

1、本地写

2、rpc写

如果rpc失败了,用户一看报错就溜了。此时数据不一致了。但是用户下次操作,仍然会从这个报错的地方开始。无形中形成了重试机制,所以能有再次执行rpc的机会。这种场景,本地写和rpc写可以放在一次,允许短暂的数据不一致情况(或者数据不一致和这个人绑定,对其他人的其他数据,没有影响)

  • 场景3:

两个写操作(相同的db,不同的表。但都是本地写),直接事务包一起即可

1.2 transaction事务注解

  • 本地的两个表的写操作一定要加事务注解

  • rpc 写和 本地的写操作,可以使用最大努力重试异步,保证成功。或者是 job触发的,可以在保证幂等的情况下,执行3次job。同样能达到重试的机制

  • 本地的写操作 &&一些列rpc操作:事务最大努力重试保证成功

@Transaction{

     本地写
     @最大努力重试
     rpc

}

二、@Transactional使用注意事项

2.1 踩坑-Methods should not call same-class methods with incompatible “@Transactional” values问题

方法和调用事务的方法,在同一个类中

  • 问题描述

    @Transactional 同一个类中无事务方法a()内部调用有事务方法b()的问题

  • 解决

    ((RdcRefundOutboundBillStatusChangeJob) AopContext.currentProxy()).processBill(bill, param.getDestroyDayLimit())
    
    @Transactional(rollbackFor = Exception.class)
    public boolean processBill(RefundOutboundBillPO bill, int destroyDayLimit) {
      
    }
    
    @Component
    public class AsyncService implements ApplicationContextAware {
    
        private ApplicationContext applicationContext;
    
        public void async1() {//类的某个方法a
            // 使用AppicationContext来获得动态代理的bean,然后再执行你调用的方法
            this.applicationContext.getBean(AsyncService.class).async2();
        }
    
        @Transactional
        public void async2() {
           //本地事务1
          //本地事务2
        }
    
        // 注入ApplicationContext
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }
    

2.1、事务使用注意事项

https://www.cnblogs.com/keeya/p/11180612.html

2.2、事务失效场景

https://segmentfault.com/a/1190000040129676

https://zhuanlan.zhihu.com/p/339536376

类上时,该类所有的public方法都会开启事务;放在方法上时,表示当前方法支持事务,必须在public方法上才可以
需要加在实现类上,而不是方法上
在@Transactional注解中有一个属性rollbackFor,这个属性设置的是发生什么类型的异常时事务进行回滚,默认的是RuntimeException。

2.3、踩坑-多数据源,某一数据源未配置事务name,导致事务失效

  • 问题描述

    NoUniqueBeanDefinitionException: No qualifying bean of type ‘org.springframework.transaction.PlatformTransactionManager’ available: expected single matching bean but found 2: default

  • 原因

    原因

    多数据源的时候

    1、第一个数据源,事务默认名称为default,第二个数据源事务名称为sale

    2、当第一个数据源,使用事务,但是,没有指定事务处理器,就会报这个错误。

    3、因为每个数据源都有自己的事务配置,单纯地用@Transactional 没法确定是哪个事务处理

你可能感兴趣的:(java,Transaction,事务,最大努力重试)