参考链接: link
-
事务管理器
<bean id="transactionManagerivc" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="ivcDataSource"></property> </bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
系统使用多数据源,此处以两个数据源做测试
-
注解
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Inherited public @interface MultiTransactional { String[] transactionManagers(); }
此处Inherited为了继承可用,可有可无
-
asp
@Aspect @Component public class TestAspect { private static final ThreadLocal<Stack<Pair<DataSourceTransactionManager, TransactionStatus>>> THREAD_LOCAL = new ThreadLocal<>(); @Autowired private ApplicationContext applicationContext; private DefaultTransactionDefinition def = new DefaultTransactionDefinition(); { // 非只读模式 def.setReadOnly(false); // 事务隔离级别:采用数据库的 def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT); // 事务传播行为 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); } @Pointcut("@annotation(cn.hsa.htp.hitotax.CBXX001.service.MultiTransactional)") public void pointcut(){} @Before(value = "pointcut() && @annotation(transactional)") public void before(MultiTransactional transactional) { // 根据设置的事务名称按顺序声明,并放到ThreadLocal里 String[] transactionManagerNames = transactional.transactionManagers(); Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = new Stack<>(); for (String transactionManagerName : transactionManagerNames) { DataSourceTransactionManager transactionManager = applicationContext.getBean(transactionManagerName, DataSourceTransactionManager.class); TransactionStatus transactionStatus = transactionManager.getTransaction(def); pairStack.push(new Pair(transactionManager, transactionStatus)); } THREAD_LOCAL.set(pairStack); } @AfterReturning("pointcut()") public void afterReturning() { // ※栈顶弹出(后进先出) Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = THREAD_LOCAL.get(); while (!pairStack.empty()) { Pair<DataSourceTransactionManager, TransactionStatus> pair = pairStack.pop(); pair.getKey().commit(pair.getValue()); } THREAD_LOCAL.remove(); } /** * 回滚事务 */ @AfterThrowing(value = "pointcut()") public void afterThrowing() { // ※栈顶弹出(后进先出) Stack<Pair<DataSourceTransactionManager, TransactionStatus>> pairStack = THREAD_LOCAL.get(); while (!pairStack.empty()) { Pair<DataSourceTransactionManager, TransactionStatus> pair = pairStack.pop(); pair.getKey().rollback(pair.getValue()); } THREAD_LOCAL.remove(); } }
4.测试
@Override
@MultiTransactional(transactionManagers = {"transactionManagerivc", "transactionManager"})
public ReturnT<String> execute(String s) throws Exception {
try {
String psnNo = "123";
String psnName = "456";
Integer integer1 = ylLhjy0318DAO.insertSheet1(psnNo, psnName);
XxlJobLogger.log("" + integer1);
Integer integer2 = hiTestDAO.insertSheet1(psnNo, psnName);
XxlJobLogger.log("" + integer2);
}catch (Exception e){
XxlJobLogger.log("######### error: " + e, e);
LOGGER.info("######### error: ", e);
XxlJobLogger.log(e);
throw e;
}
return SUCCESS;
}
测试方法很简单,随便建两张表,设置主键,然后重复插入数据导致报错
5.遇到的坑
在catch中,如果不throw,则直接进入AfterReturning,故必须throw才能生效