
1. 分布式事务与本地事务的冲突本质在Spring Boot3应用中同时使用分布式事务和本地事务时最典型的冲突场景发生在事务传播行为(Propagation Behavior)的边界处。当某个服务方法同时涉及数据库本地操作和跨服务调用时两种事务管理器的协调问题会导致以下现象事务悬挂本地事务管理器(如DataSourceTransactionManager)提交后分布式事务管理器(如Seata)尚未完成全局提交此时其他事务读取到中间状态数据脏读风险分布式事务回滚时已提交的本地事务无法回滚造成数据不一致死锁陷阱不同事务管理器持有的锁相互等待形成分布式死锁这种冲突的根本原因在于两种事务管理器对资源的管理是割裂的。本地事务管理器只能感知到当前数据源连接而分布式事务管理器需要协调多个服务的资源。当它们同时作用于同一业务链路时就会形成两个指挥官同时指挥一支军队的局面。2. 事务管理器的隔离方案设计2.1 物理隔离服务分层架构最彻底的解决方案是通过架构设计实现事务管理器的物理隔离。建议采用分层服务设计┌───────────────────────┐ │ API Service │ ← 只处理HTTP请求/响应 ├───────────────────────┤ │ Business Service │ ← 只使用分布式事务 ├───────────────────────┤ │ Domain Service │ ← 只使用本地事务 └───────────────────────┘具体实现要点领域服务层(Domain Service)仅包含与单一数据库强相关的操作使用Transactional注解管理本地事务业务服务层(Business Service)编排多个领域服务使用GlobalTransactional注解管理分布式事务API服务层仅做协议转换不包含任何事务注解提示这种分层需要团队严格遵循代码规范可以通过ArchUnit编写架构测试来强制约束2.2 逻辑隔离事务传播策略当无法进行物理隔离时可以通过精细控制事务传播行为来降低冲突概率Service public class OrderService { // 分布式事务入口 GlobalTransactional public void createOrder(OrderDTO dto) { // 需要本地事务的操作使用REQUIRES_NEW传播 localOperationWithNewTx(); remoteService.call(); } Transactional(propagation Propagation.REQUIRES_NEW) public void localOperationWithNewTx() { // 独立的新事务 } }关键传播行为选择REQUIRES_NEW始终新建事务适合必须提交的本地操作NOT_SUPPORTED挂起当前事务适合不需要事务的查询NEVER强制不能有事务适合第三方不可控调用3. 混合事务模式下的补偿机制3.1 本地消息表实现当分布式事务回滚时已提交的本地事务需要通过补偿机制处理。本地消息表是最常用的解决方案CREATE TABLE local_message ( id BIGINT PRIMARY KEY, biz_id VARCHAR(64) NOT NULL, payload JSON NOT NULL, status TINYINT NOT NULL, -- 0:初始 1:已发送 2:已完成 created_at TIMESTAMP NOT NULL );Spring Boot实现示例Transactional public void saveOrderWithMessage(Order order) { // 1. 本地事务保存订单 orderRepository.save(order); // 2. 同一事务保存消息 LocalMessage message new LocalMessage(); message.setBizId(order.getNo()); message.setPayload(toJson(order)); messageRepository.save(message); } // 定时任务扫描未发送消息 Scheduled(fixedRate 5000) public void processPendingMessages() { ListLocalMessage messages messageRepository.findByStatus(0); messages.forEach(msg - { try { mqTemplate.convertAndSend(order.create, msg.getPayload()); messageRepository.updateStatus(msg.getId(), 1); } catch (Exception e) { log.error(消息发送失败, e); } }); }3.2 TCC模式适配对于需要强一致性的场景可以采用TCC(Try-Confirm-Cancel)模式public interface OrderTccService { TwoPhaseBusinessAction(name createOrder, commitMethod confirm, rollbackMethod cancel) boolean tryCreateOrder(BusinessActionContextParameter(paramName orderId) String orderId); boolean confirm(BusinessActionContext context); boolean cancel(BusinessActionContext context); } // 实现类需要处理悬挂问题 Service public class OrderTccServiceImpl implements OrderTccService { Transactional public boolean tryCreateOrder(String orderId) { // 预留资源 orderDao.insertTentative(orderId); } Transactional public boolean confirm(BusinessActionContext context) { String orderId context.getActionContext(orderId); orderDao.confirm(orderId); } Transactional public boolean cancel(BusinessActionContext context) { String orderId context.getActionContext(orderId); orderDao.cancel(orderId); } }4. Spring Boot3的特定配置要点4.1 事务管理器自动配置Spring Boot3对事务自动配置做了优化需要特别注意spring: transaction: default-timeout: 30s # 默认事务超时 rollback-on-commit-failure: true # 提交失败时回滚多数据源场景需要手动定义事务管理器Configuration EnableTransactionManagement public class TransactionConfig { Bean Primary public PlatformTransactionManager primaryTxManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } Bean public GlobalTransactionScanner globalTransactionScanner() { return new GlobalTransactionScanner(app-name, my-tx-group); } }4.2 WebClient与事务协调Spring Boot3的WebClient在事务中使用时需要注意Transactional public void processWithRemoteCall() { // 本地数据库操作 repo.save(entity); // 异步HTTP调用需要事务传播 webClient.post() .uri(/api/process) .retrieve() .bodyToMono(Void.class) .block(); // 必须阻塞等待 // 后续本地操作 }关键注意事项必须使用block()同步等待响应否则事务可能提前提交考虑设置合理的超时webClient.mutate().filter(timeoutFilter).build()建议将远程调用封装在Transactional(propagation REQUIRES_NEW)方法中5. 实战中的典型问题排查5.1 事务未回滚诊断当发现事务未按预期回滚时按以下步骤排查检查异常类型默认只回滚RuntimeException和ErrorTransactional(rollbackFor Exception.class) // 扩展回滚范围查看代理模式spring.aop.proxy-target-classtrue # 需要CGLIB代理确认是否跨线程// 错误示例异步方法内的事务不生效 Async Transactional public void asyncMethod() {}5.2 连接泄漏检测混合事务模式下容易出现的连接泄漏问题Bean public DataSource dataSource() { HikariDataSource ds new HikariDataSource(); ds.setLeakDetectionThreshold(5000); // 5秒泄漏检测 return ds; } // 在日志中搜索Connection leak detection5.3 分布式锁冲突使用Redisson处理分布式锁时的注意事项GlobalTransactional public void distributedOperation() { RLock lock redissonClient.getLock(resource_lock); try { // 锁超时应小于事务超时 if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { // 业务操作 } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }6. 性能优化实践6.1 批量操作优化混合事务中的批量处理建议Transactional public void batchInsert(ListEntity list) { // 每500条提交一次 int batchSize 500; for (int i 0; i list.size(); i batchSize) { ListEntity subList list.subList(i, Math.min(i batchSize, list.size())); jdbcTemplate.batchUpdate(INSERT..., subList); // 手动刷新会话 entityManager.flush(); entityManager.clear(); } }6.2 事务隔离级别调整根据业务场景调整隔离级别Transactional(isolation Isolation.READ_COMMITTED) public void readOperation() { // 读已提交级别 } Transactional(isolation Isolation.REPEATABLE_READ) public void writeOperation() { // 可重复读级别 }6.3 监控与指标收集集成Micrometer监控事务指标Bean public MeterRegistryCustomizerMeterRegistry metricsCommonTags() { return registry - registry.config().commonTags( application, order-service, transaction.type, mixed ); } // 在Prometheus中监控 // spring_transactions_active{applicationorder-service} // spring_transactions_committed_total{statusmixed}