本文展示的代码均以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() {
// 做一些数据库更新操作
}
}
如有问题请留言。