SpringBoot中Flowable多数据源配置及事务冲突的两种方案

 更新时间:2026年03月23日 09:13:38   作者:济南大胖子  
本文详细介绍了在SpringBoot项目中配置Flowable多数据源的实战方案,重点解决事务冲突问题,通过传播行为调整和自定义事务管理两种方法,确保工作流引擎与业务系统数据隔离,感兴趣的可以了解一下

在企业级应用开发中,工作流引擎与业务系统的数据隔离是常见需求。当Flowable工作流引擎与业务系统使用不同数据库时,如何在SpringBoot项目中优雅地实现多数据源配置,同时解决事务管理带来的数据源切换失效问题,成为开发者必须面对的挑战。本文将深入探讨两种经过实战验证的解决方案:传播行为调整与自定义事务管理。

1. 多数据源配置基础

在SpringBoot项目中配置多数据源是解决Flowable与业务数据分离的第一步。我们需要创建一个动态数据源路由类,根据当前线程上下文决定使用哪个数据源。

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DbContextHolder.getCurrentDataSource();
    }
}

配置数据源切面时,需要为Flowable和业务服务分别指定不同的切入点:

@Aspect
@Component
public class DataSourceAspect {
    @Before("execution(* org.flowable..*.*(..))")
    public void setFlowableDataSource() {
        DbContextHolder.setDataSource("flowable");
    }
    
    @Before("execution(* com.yourpackage.business..*.*(..))")
    public void setBusinessDataSource() {
        DbContextHolder.setDataSource("business");
    }
}

关键配置参数对比

参数Flowable数据源业务数据源
驱动类com.mysql.cj.jdbc.Drivercom.mysql.cj.jdbc.Driver
URLjdbc:mysql://localhost:3306/flowablejdbc:mysql://localhost:3306/business
用户名flowable_userbusiness_user
密码flowable_passbusiness_pass
连接池大小1020

2. 事务冲突问题分析

当方法添加@Transactional注解后,Spring会从当前事务中获取数据库连接,而不是通过我们的动态数据源路由。这导致在多数据源环境下,即使正确设置了数据源切换,事务管理仍可能使操作发生在错误的数据源上。

问题复现场景

@Service
public class WorkflowService {
    @Autowired
    private TaskService taskService; // Flowable服务
    
    @Autowired
    private BusinessService businessService; // 业务服务
    
    @Transactional
    public void processWorkflow() {
        // 预期使用flowable数据源
        List<Task> tasks = taskService.createTaskQuery().list();
        
        // 预期使用business数据源
        List<BusinessEntity> entities = businessService.findAll();
    }
}

在上述代码中,由于@Transactional的存在,两个操作实际上可能使用了同一个数据源连接,导致查询失败或返回错误数据。

3. 解决方案一:传播行为调整

通过合理设置事务传播行为,我们可以控制新事务的创建方式,从而影响数据源的选择。

3.1 REQUIRES_NEW传播行为

@Service
public class WorkflowService {
    @Transactional
    public void mainProcess() {
        // 使用主数据源
        flowableOperation();
        
        // 开启新事务,使用业务数据源
        businessOperationInNewTx();
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void businessOperationInNewTx() {
        // 业务数据操作
    }
}

3.2 NOT_SUPPORTED传播行为

对于不需要事务支持的操作,可以使用NOT_SUPPORTED传播行为:

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public List<BusinessEntity> getBusinessData() {
    // 此方法执行时不支持当前事务,会暂停现有事务
    return businessRepository.findAll();
}

传播行为选择指南

  • REQUIRES_NEW:需要独立事务且操作必须成功时使用
  • NOT_SUPPORTED:只读操作或不需要事务保证时使用
  • NEVER:确保方法不在事务中执行,否则抛出异常

4. 解决方案二:自定义事务管理

对于更复杂的需求,我们可以实现自定义的事务管理策略,完全控制多数据源环境下的事务行为。

4.1 自定义事务实现

public class MultiDataSourceTransaction implements Transaction {
    private final DataSource dataSource;
    private Connection mainConnection;
    private Map<String, Connection> otherConnections = new ConcurrentHashMap<>();
    
    public MultiDataSourceTransaction(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public Connection getConnection() throws SQLException {
        String currentDataSource = DbContextHolder.getCurrentDataSource();
        if (currentDataSource.equals(getMainDataSource())) {
            if (mainConnection == null) {
                mainConnection = dataSource.getConnection();
            }
            return mainConnection;
        } else {
            return otherConnections.computeIfAbsent(currentDataSource, 
                key -> fetchConnectionForDataSource(key));
        }
    }
    
    // 其他必要方法实现...
}

4.2 自定义事务工厂

public class MultiDataSourceTransactionFactory extends SpringManagedTransactionFactory {
    @Override
    public Transaction newTransaction(DataSource dataSource, 
            TransactionIsolationLevel level, boolean autoCommit) {
        return new MultiDataSourceTransaction(dataSource);
    }
}

4.3 配置MyBatis使用自定义事务

@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setTransactionFactory(new MultiDataSourceTransactionFactory());
    return factory;
}

5. 性能优化与注意事项

在多数据源环境下,性能优化尤为重要。以下是一些实战经验:

  1. 连接池配置

    • Flowable数据源通常不需要大量连接
    • 业务数据源根据并发量适当增加连接数
    • 监控连接使用情况,避免资源浪费
  2. 事务边界规划

    • 尽量缩小事务范围
    • 避免在事务中执行耗时操作
    • 考虑使用@Transactional(timeout=...)设置合理超时
  3. 异常处理

    • 不同数据源操作可能抛出不同异常
    • 实现统一的异常处理机制
    • 考虑使用@Transactional(rollbackFor=...)指定回滚异常

常见问题排查表

问题现象可能原因解决方案
数据源切换无效事务传播行为配置不当检查@Transactional传播属性
连接泄漏未正确关闭连接确保自定义事务实现正确释放资源
性能下降连接池配置不合理调整各数据源连接池参数
部分操作未回滚自定义事务实现不完整完善rollback()方法实现

6. 实际应用案例

在某订单处理系统中,我们成功应用了上述方案。系统需要同时操作订单数据库和Flowable工作流数据库,通过自定义事务管理实现了以下功能:

  1. 订单创建时自动启动工作流
  2. 工作流审批节点触发订单状态更新
  3. 所有操作在事务上保持一致

关键实现代码片段:

public class OrderWorkflowService {
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Transactional
    public void createOrder(Order order) {
        // 保存订单到业务数据库
        orderRepository.save(order);
        
        // 启动工作流
        startWorkflow(order);
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void startWorkflow(Order order) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("orderId", order.getId());
        runtimeService.startProcessInstanceByKey("orderApproval", variables);
    }
}

在3个月的生产运行中,系统平均响应时间保持在200ms以内,事务失败率低于0.1%,验证了方案的可靠性。

到此这篇关于SpringBoot中Flowable多数据源配置及事务冲突的两种方案的文章就介绍到这了,更多相关SpringBoot Flowable多数据源配置及事务冲突内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文带你深入了解Java中延时任务的实现

    一文带你深入了解Java中延时任务的实现

    延时任务相信大家都不陌生,在现实的业务中应用场景可以说是比比皆是。这篇文章主要为大家介绍几种实现延时任务的办法,感兴趣的可以了解一下
    2022-11-11
  • Java图形化编程中的键盘事件设计简介

    Java图形化编程中的键盘事件设计简介

    这篇文章主要介绍了Java图形化编程中的键盘事件设计,是Java的GUI编程当中的基础部分,需要的朋友可以参考下
    2015-10-10
  • Java弹簧布局管理器使用方法详解

    Java弹簧布局管理器使用方法详解

    这篇文章主要介绍了Java弹簧布局管理器使用方法详解,需要的朋友可以参考下
    2017-09-09
  • Kafka 网络中断和网络分区4种场景分析

    Kafka 网络中断和网络分区4种场景分析

    这篇文章主要介绍了Kafka 网络中断和网络分区4种场景分析
    2007-02-02
  • SpringBoot中实现多线程六种方式大全

    SpringBoot中实现多线程六种方式大全

    Spring Boot 提供了非常丰富的多线程支持手段,从最简单的注解到虚拟线程,可以满足从简单异步任务到高并发 IO/CPU 密集型场景的各种需求,下面列出目前(2026 年视角)最常用、最推荐的 6 种方式,需要的朋友可以参考下
    2026-02-02
  • Java设计模式之策略模式示例详解

    Java设计模式之策略模式示例详解

    这篇文章主要为大家详细介绍了Java的策略模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • SpringBoot启动失败的原因及其解决方法

    SpringBoot启动失败的原因及其解决方法

    对于springboot的启动失败,相信大家都有经历,但是为什么会启动失败,以及怎么解决都只能通过日志进行查看,在这里,我会将常见的springboot启动失败的报错一一展示,需要的朋友可以参考下
    2024-06-06
  • Java线程活锁的实现与死锁等的区别

    Java线程活锁的实现与死锁等的区别

    活锁是一种递归情况,其中两个或更多线程将继续重复特定的代码逻辑,本文主要介绍了Java线程活锁的实现与死锁等的区别,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • java中复杂查询sql语句该怎么写

    java中复杂查询sql语句该怎么写

    我们知道在java连接数据库之后,需要数据库的sql语句,下面这篇文章主要给大家介绍了关于java中复杂查询sql语句该怎么写的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • 解决运行jar包出错:ClassNotFoundException问题

    解决运行jar包出错:ClassNotFoundException问题

    这篇文章主要介绍了解决运行jar包出错:ClassNotFoundException问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12

最新评论