# Transactional声明式事务失效解决方案

# 场景

在同一个service中,A方法需要调用B方法,且在B方法开启声明式事务。我们简单的在A方法中以this.B()的方式调用B方法,出现异常后,事务未按预期的回滚,事务失效。

# 原因

我们首先要搞清楚一个问题,事务是何时开启的(以方法A举例,在A方法上标注@Transactional注解,开启声明式事务)

在以xxxService.A()的方式调用A方法时,事务开启。在使用this.A()方式调用A方法时,将无法识别到@Transactional注解

# 解决方案

# 在A方法中改以xxxService.B()的方式调用B方法

  • 第一种写法

    将当前Service以懒加载的方式注入

    @Service
    public class XxxServiceImpl {
      
      @Autowired
      @Lazy
      private XxxService xxxService;
      
      public void A() {
        // do something
        xxxService.B();
        // do something
      }
      
      @Transactional
      public void B() {
        // do something
      }
    }
    
    
  • 第二种写法

    从Spring的上下文中获取当前Service

    @Component
    public class ApplicationContextHolder implements ApplicationContextAware {
        private static ApplicationContext context;
    
        private ApplicationContextProvider() {
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            context = applicationContext;
        }
    
        public static <T> T getBean(Class<T> aClass) {
            return context.getBean(aClass);
        }
    
        @SuppressWarnings("unchecked")
        public static <T> T getBean(String name) {
            return (T) context.getBean(name);
        }
    }
    
    @Service
    public class XxxServiceImpl {
      
      public void A() {
        // do something
        ApplicationContextHolder.getBean(XxxService.class).B();
        // do something
      }
      
      @Transactional
      public void B() {
        // do something
      }
    }
    

# 编程式事务

  • 第一种写法

    ExecutorService executorService = Executors.newSingleThreadExecutor();
    executorService.submit(() -> {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = txManager.getTransaction(def);
    
        try {
            // do something
    
            // 提交事务
            txManager.commit(status);
        } catch (Exception e) {
            Throwables.getStackTraceAsString(e);
            // 删除失败,将云环境状态还原
           	// do something...
    
            // 回滚事务
            txManager.rollback(status);
        } finally {
            // do something
        }
    });
    
  • 第二写法

    TransactionTemplate template = new TransactionTemplate(txManager);
    template.execute(new TransactionCallback<Void>() {
        @Override
        public Void doInTransaction(TransactionStatus status) {
            try {
                // do something
    
                // 提交事务
                 txManager.commit(status);
            } catch (Exception e) {
                Throwables.getStackTraceAsString(e);
    
                // 回滚事务
                txManager.rollback(status);
    
                // do something
            } finally {
               // do something
            }
    
            return null;
        }
    });
    
Last Updated: 12/2/2021, 9:29:16 PM