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多数据源配置及事务冲突内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring注解@Scope原理及用法解析

    Spring注解@Scope原理及用法解析

    这篇文章主要介绍了Spring注解@Scope原理及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • SpringBoot实现接口校验签名调用的项目实践

    SpringBoot实现接口校验签名调用的项目实践

    在以SpringBoot开发后台API接口时,会存在哪些接口不安全的因素呢?通常如何去解决的呢?本文主要介绍了SpringBoot实现接口校验签名调用的项目实践,感兴趣的可以了解一下
    2023-09-09
  • Java实现冒泡排序算法及对其的简单优化示例

    Java实现冒泡排序算法及对其的简单优化示例

    这篇文章主要介绍了Java实现冒泡排序算法及对其的简单优化示例,冒泡排序的最差时间复杂度为O(n^2),最优时间复杂度为O(n),存在优化的余地,需要的朋友可以参考下
    2016-05-05
  • Java中实体与Map之间的相互转换代码示例

    Java中实体与Map之间的相互转换代码示例

    生活中经常用到map数据与实体类的转换,下面这篇文章主要给大家介绍了关于Java中实体与Map之间相互转换的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • Java使用BigDecimal确保数值计算精度的最佳实践指南

    Java使用BigDecimal确保数值计算精度的最佳实践指南

    这篇文章主要为大家详细介绍了Java使用BigDecimal确保数值计算精度的相关知识,BigDecimal一般适用于金融计算、高精度运算等对数值准确性要求高的场景,下面小编就和大家详细介绍一下吧
    2026-01-01
  • Java多线程中Lock锁的使用小结

    Java多线程中Lock锁的使用小结

    这篇文章主要介绍了Java多线程中Lock锁的使用小结,本节主要讲了它的基本使用,大家可以举一反三,试试什么条件下会导致死锁,需要的朋友可以参考下
    2022-06-06
  • Jedis操作Redis数据库的方法

    Jedis操作Redis数据库的方法

    这篇文章主要为大家详细介绍了Jedis操作Redis数据库的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • 深入理解SpringBoot 最大连接数及最大并发数

    深入理解SpringBoot 最大连接数及最大并发数

    SpringBoot能支持的最大并发量主要看其对Tomcat的设置,可以在配置文件中对其进行更改,本文就来介绍一下SpringBoot 最大连接数及最大并发数,感兴趣的可以了解一下
    2023-08-08
  • SpringCloud实战之Zuul网关服务

    SpringCloud实战之Zuul网关服务

    服务网关是分布式架构中不可缺少的组成部分,是外部网络和内部服务之间的屏障。这篇文章主要介绍了SpringCloud实战之Zuul网关服务。一起跟随小编过来看看吧
    2018-05-05
  • Spring Boot 中的 @Field 注解的原理解析

    Spring Boot 中的 @Field 注解的原理解析

    本文详细介绍了 Spring Boot 中的 @Field 注解的原理和使用方法,通过使用 @Field 注解,我们可以将 HTTP 请求中的参数值自动绑定到 Java 对象的属性上,简化了开发过程,提高了开发效率,感兴趣的朋友跟随小编一起看看吧
    2023-07-07

最新评论