多数据源事务提交

本文展示的代码均以Spring为基础,使用切面的方式进行多数据源事务提交。

1. 数据源配置

定义了2个数据源和2个事务管理器。

<!-- 定义数据源 -->
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url2}" />
    <property name="username" value="${jdbc.username2}" />
    <property name="password" value="${jdbc.password2}" />
</bean>

<!-- 定义事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource2"/>
</bean>

2. 编写切面相关代码

2.1 自定义注解

此注解用于方法上面,进行事务关联。

import java.lang.annotation.ElemntType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
public @interface MultiTxManager {
    /**
     * 事务管理器名称
     */
    String[] txManagerNames() default {};
}

2.2 切面代码

用于事务提交和回滚。事务管理器的2大作用:提交和回滚。


import org.apache.commons.collections4.CollectionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Stack;

@Aspect
@Component
public class SelfTxManagerAspect {

    @Resource
    private ApplicationContext context;

    /**
     * 定义切点
     */
    @Pointcut("@annotation(MultiTxManager)")
    public void pointCut() {
    }

    /**
     * 环绕
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        MultiTxManager tm = method.getAnnotation(MultiTxManager.class);

        // 事务管理器
        Stack<DataSourceTransactionManager> tmStack = new Stack<>();
        // 事务状态
        Stack<TransactionStatus> tsStack = new Stack<>();

        // 是否需要开启事务标识
        boolean enableTransaction = true;
        if (tm.txManagerNames().length < 1) {
            enableTransaction = false;
        }

        if (enableTransaction ) {
            for(String tmName : tm.txManagerNames()) {
                DataSourceTransactionManager dtxm = context.getBean(tmName,DataSourceTransactionManager.class);
                if (dtxm == null) { continue; }
                // 开启事务
                TransactionStatus ts = dtxm.getTransaction(new DefaultTransactionDefinition());
                tmStack.push(dtxm);
                tsStack.push(ts);
            }
        }
        if (CollectionUtils.isEmpty(tmStack)) {
            enableTransaction = false;
        }
        try {
            Object result = point.proceed();
            // 方法执行完成,若有事务则提交
            while (enableTransaction && !tmStack.isEmpty()) {
                DataSourceTransactionManager manager = tmStack.pop();
                TransactionStatus status = tsStack.pop();
                manager.commit(status);
            }
            return result;
        } catch (Throwable e) {
            // 发生异常时回滚
            while (enableTransaction && !tmStack.isEmpty()) {
                DataSourceTransactionManager manager = tmStack.pop();
                TransactionStatus status = tsStack.pop();
                manager.rollback(status);
            }
            throw e;
        }
    }
}

2.3 在方法上应用


public class xxxxServiceImpl {

    @MultiTxManager(txManagerNames={"txManager", "txManager2"})
    public Object saveOrUpdate() {
        // 做一些数据库更新操作
    }
}

如有问题请留言。