dynamic-datasource异步事务:多数据源协调
你是否在处理多数据源时遇到过事务不一致的问题?当订单系统需要同时操作用户账户、商品库存和订单数据时,如何确保跨库操作的原子性?本文将介绍如何使用dynamic-datasource的异步事务功能,通过简单配置实现多数据源间的事务协调,确保数据一致性。读完本文后,你将能够:掌握@DSTransactional注解的使用方法、理解多数据源事务协调原理、解决分布式系统中的数据一致性问题。
什么是异步事务与多数据源协调
在分布式系统中,一个业务操作往往需要跨多个数据库执行,这就是多数据源场景。异步事务(Asynchronous Transaction)则是指事务的提交或回滚操作在后台异步完成,避免长时间阻塞主线程。dynamic-datasource通过分布式事务(Distributed Transaction)机制,确保多个数据源间的数据操作要么全部成功,要么全部失败,从而解决数据不一致问题。
核心组件解析
@DSTransactional注解
该注解是实现多数据源事务的核心,用于标记需要事务管理的方法。通过设置回滚异常、传播行为等属性,控制事务的执行逻辑。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DSTransactional {
Class<? extends Throwable>[] rollbackFor() default {Exception.class};
Class<? extends Throwable>[] noRollbackFor() default {};
DsPropagation propagation() default DsPropagation.REQUIRED;
}
事务上下文(TransactionContext)
用于管理事务ID(XID)和同步信息,确保事务在多数据源间的一致性。主要功能包括绑定/解绑事务ID、注册事务同步器等。
public class TransactionContext {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
private static final ThreadLocal<Set<TransactionSynchronization>> SYNCHRONIZATION_HOLDER =
ThreadLocal.withInitial(LinkedHashSet::new);
public static String getXID() { ... }
public static void registerSynchronization(TransactionSynchronization synchronization) { ... }
}
源码位置:dynamic-datasource-spring/src/main/java/com/baomidou/dynamic/datasource/tx/TransactionContext.java
事务拦截器(DynamicLocalTransactionInterceptor)
AOP拦截器,负责在方法执行前后处理事务逻辑,如开启事务、提交/回滚事务等。
public class DynamicLocalTransactionInterceptor implements MethodInterceptor {
@Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
TransactionalExecutor transactionalExecutor = new TransactionalExecutor() {
@Override
public Object execute() throws Throwable {
return methodInvocation.proceed();
}
// ...
};
return transactionalTemplate.execute(transactionalExecutor);
}
}
实现原理
多数据源事务协调的核心流程如下:
使用步骤
1. 添加依赖
在Spring Boot项目的pom.xml中添加dynamic-datasource starter依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
2. 配置多数据源
在application.yml中配置多个数据源:
spring:
datasource:
dynamic:
primary: master
datasources:
master:
url: jdbc:mysql://localhost:3306/master
username: root
password: 123456
slave_1:
url: jdbc:mysql://localhost:3306/slave_1
username: root
password: 123456
slave_2:
url: jdbc:mysql://localhost:3306/slave_2
username: root
password: 123456
3. 使用@DSTransactional注解
在需要事务管理的方法上添加@DSTransactional注解:
@Service
public class OrderService {
@Autowired
private AccountService accountService;
@Autowired
private ProductService productService;
@DSTransactional(rollbackFor = Exception.class)
public void placeOrder(PlaceOrderRequest request) {
// 扣减库存
productService.reduceStock(request.getProductId(), request.getAmount());
// 扣减余额
accountService.reduceBalance(request.getUserId(), request.getTotalPrice());
// 创建订单
createOrder(request);
}
}
4. 注册事务同步器(可选)
通过TransactionContext注册事务同步器,在事务完成后执行额外操作:
@DSTransactional
public void placeOrder(PlaceOrderRequest request) {
TransactionContext.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCompletion(int status) {
if (status == STATUS_COMMITTED) {
// 发送订单成功消息
sendOrderSuccessMessage(request.getOrderId());
}
}
});
// 业务逻辑...
}
注意事项与最佳实践
- 传播行为选择:根据业务场景选择合适的事务传播行为,默认值为
DsPropagation.REQUIRED。 - 避免长事务:异步事务虽然不会阻塞主线程,但长事务仍会占用数据库连接,影响系统性能。
- 异常处理:明确指定
rollbackFor和noRollbackFor,避免事务无法正确回滚。 - 测试验证:通过单元测试验证事务的提交和回滚是否符合预期,示例测试类:dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/v1/DsTransactionalTest.java
总结与展望
dynamic-datasource通过@DSTransactional注解、事务上下文和拦截器等组件,实现了多数据源间的事务协调,解决了分布式系统中的数据一致性问题。使用该功能可以简化多数据源事务管理的复杂度,提高系统的可靠性。未来,dynamic-datasource可能会支持更多事务模式(如TCC、SAGA),进一步满足复杂业务场景的需求。
官方文档:README.md
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



