# 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; } });