Spring中实现多数据源事务管理

Spring中实现多数据源事务管理前言

由于项目中引入了多个数据源,并且需要对多个数据源进行写操作,那么多数据源的事务管理自然成了不可避免的问题,这也让我对@Transactional注解有了进一步的理解(但实际上也并不是非常深入)

然而这是一个演进的过程,刚开始项目中并没有使用@Transactional指定具体的TransactionManager,所以新增一个数据源后,对原有的事务产生了影响了,这也是偶尔在一次测试报错而结果没有回滚之后才发现的,遂对于@Transactional注解的一些参数项进行了了解。

研究

由于容器中存在两个TransactionManager,那么被@Transactional注解的方法到底使用了哪个TransactionManager来进行事务管理,抑或是同时使用了两个TransactionManager来进行事务管理都是我们需要搞清楚的问题。 首先我们先看看@Transactional注解上有没有提供配置项来指定TransactionManager,果不其然,发现value属性就是用来指定具体TransactionManager的,通过id或者name来指定唯一一个TransactionManager,那么对于只需要一个事务管理的方法,问题就简单多了:

@Transactional(value = “database2TransactionManager”)(String a) {// business operation}

关于不指定TransactionManager时会使用哪一个TransactionManager,有兴趣的童鞋可以参考另一篇文章,讲的比较清晰:

好了,回到我们研究的问题,那么对于需要写入多个数据源的业务方法该怎么办呢?

进一步研究

看来@Transactional是没有提供这种功能了,那么就自己写了一个吧。我记得Spring中的事务管理分编程式事务和声明式事务。我们平时使用的@Transactional就是声明式事务,它的好处其实也就是灵活度更高、代码的耦合性更低,最终的事务管理实现还是一样的,只不过将具体逻辑都剥离到了切面中。所以我们可以手写一个切面来写一次“编程式事务”,,当然在具体应用时,还是声明式的。

Java中一般编程式事务的写法:

{@Resourceprivate TransactionManager txManager;@Resourceprivate UserDao userDao;@Resourceprivate AddressDao addressDao;(User user) {TransactionDefinition txDefinition = new TransactionDefinition();TransactionStatus txStatus = txManager.getTransaction(txDefinition);boolean result = false;try {result = userDao.save(user);if(!result){return false;}result = addressDao.save(user.getId(), user.getAddress());txManager.commit(txStatus);} catch (Exception e) {result = false;txManager.rollback(txStatus);}return result;}}

我们借用这个逻辑将事务管理相关提取到切面中,并在进入目标方法之前,让多个TransactionManager都开启事务,并在成功执行后一并提交或失败后一并回滚,具体代码:

/** * @author Zhu * @date 2015-7-15 * @version 0.0.1 * @description */{private Logger logger = LoggerFactory.getLogger(getClass());public Object around(ProceedingJoinPoint pjp,MultiTransactional multiTransactional) throws Throwable {Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack = new Stack<DataSourceTransactionManager>();Stack<TransactionStatus> transactionStatuStack = new Stack<TransactionStatus>();try {if (!openTransaction(dataSourceTransactionManagerStack,transactionStatuStack, multiTransactional)) {return null;}Object ret = pjp.proceed();commit(dataSourceTransactionManagerStack, transactionStatuStack);return ret;} catch (Throwable e) {rollback(dataSourceTransactionManagerStack, transactionStatuStack);logger.error(String.format(“MultiTransactionalAspect, method:%s-%s occors error:”, pjp.getTarget().getClass().getSimpleName(), pjp.getSignature().getName()), e);throw e;}}/*** @author Zhu* @date 2015-7-25下午7:55:46* @description* @param dataSourceTransactionManagerStack* @param transactionStatuStack* @param values*/(Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,Stack<TransactionStatus> transactionStatuStack,MultiTransactional multiTransactional) {String[] transactionMangerNames = multiTransactional.values();if (ArrayUtils.isEmpty(multiTransactional.values())) {return false;}for (String beanName : transactionMangerNames) {DataSourceTransactionManager dataSourceTransactionManager = (DataSourceTransactionManager) ContextHolder.getBean(beanName);TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());transactionStatuStack.push(transactionStatus);dataSourceTransactionManagerStack.push(dataSourceTransactionManager);}return true;}/*** @author Zhu* @date 2015-7-25下午7:56:39* @description* @param dataSourceTransactionManagerStack* @param transactionStatuStack*/(Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,Stack<TransactionStatus> transactionStatuStack) {while (!dataSourceTransactionManagerStack.isEmpty()) {dataSourceTransactionManagerStack.pop().commit(transactionStatuStack.pop());}}/*** @author Zhu* @date 2015-7-25下午7:56:42* @description* @param dataSourceTransactionManagerStack* @param transactionStatuStack*/(Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,Stack<TransactionStatus> transactionStatuStack) {while (!dataSourceTransactionManagerStack.isEmpty()) {dataSourceTransactionManagerStack.pop().rollback(transactionStatuStack.pop());}}肯承认错误则错已改了一半

Spring中实现多数据源事务管理

相关文章:

你感兴趣的文章:

标签云: