关于流程引擎与业务如何保证数据一致性研究

14 篇文章 2 订阅
12 篇文章 7 订阅

项目背景

由于项目中使用了flowable流程引擎,然后自己在flowable基础上维护了一套自己的业务表数据。如果处理不当这样会引起 数据一致性问题。 即 我数据插入了流程引擎表,但是业务表插入失败了,二者数据不一致。如何处理? 下面详细分析一下如何处理这种情况。

问题描述

如何保证 流程引擎数据库 与 业务表数据一致性

解决方案

单机环境

大多数人看到这个问题的时候应该会想到可以通过事务来设置。

将事务管理器 transactionManager 设置进 flowable 的配置文件。

@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration>{
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private DataSource dataSource;

    @Override
    public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {

        springProcessEngineConfiguration.setActivityFontName("宋体");
        springProcessEngineConfiguration.setLabelFontName("宋体");
        springProcessEngineConfiguration.setAnnotationFontName("宋体");
        springProcessEngineConfiguration.setAsyncExecutorActivate(false);
        springProcessEngineConfiguration.setDatabaseType("mysql");
        springProcessEngineConfiguration.setDataSource(dataSource);
        // 这里设置 事务的传播属性
        springProcessEngineConfiguration.setTransactionManager(transactionManager);
    }
 }

springboot2.x 启用事务

启动类上加上 @EnableTransactionManagement 注解

方法中加上 事务注解

@Transactional

常见事务失效场景

  1. 一个有@Transactional的方法被没有@Transactional方法调用时,会导致Transactional作用失效。也是最容易出现的情况。
    由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
  2. 对非public方法进行事务注解。@Transactional 将会失效。
    由于在Spring AOP代理时,事务拦截器在目标方法前后进行拦截,DynamicAdvisedInterceptor的intercept 方法会获取Transactional注解的事务配置信息,

因为在Spring AOP 代理时,如上图所示 TransactionInterceptor (事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource的 computeTransactionAttribute 方法会间接调用 AbstractFallbackTransactionAttributeSource的 computeTransactionAttribute 方法,这个方法会获取Transactional 注解的事务配置信息。他会首先校验事务方法的修饰符是不是public,不是 public则不会获取@Transactional 的属性配置信息。
3. Transactional 事务配置属性中的propagation 属性配置的问题
当propagation属性配置为:
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。       TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。    TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常.

事务传播属性 propagation

代表事务的传播行为,默认值为Propagation.REQUIRED。

Propagation.REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。比如A方法内部调用了B方法,此时B方法将会使用A方法的事务。

Propagation.MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。

Propagation.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

Propagation.REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。比如A方法使用默认的事务传播属性,B方法使用REQUIRES_NEW,此时A方法在内部调用B方法,一旦A方法出现异常,A方法中的事务回滚了,但是B方法并没有回滚,因为A和B方法使用的不是同一个事务,B方法新建了一个事务。

Propagation.NESTED:支持当前事务,新增Savepoint点,也就是在进入子事务之前,父事务建立一个回滚点,与当前事务同步提交或回滚。子事务是父事务的一部分,在父事务还未提交时,子事务一定没有提交。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

事务隔离级别 solation

事务的隔离级别,默认是Isolation.DEFAULT。

几种值的含义如下:

Isolation.DEFAULT:事务默认的隔离级别,使用数据库默认的隔离级别。

Isolation.READ_UNCOMMITTED:这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。

Isolation.READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻读。

Isolation.REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。

Isolation.SERIALIZABLE:这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。

分布式情况下

  1. 通过分布式事务 如 seata 等处理。

衍生问题: 当我们使用MQ与外部系统对接时,如何保证流程引擎与外部系统对接时的数据一致性。

衍生问题的解决方案:

分而治之,比别人多考虑一步,将流程引擎当成一个整体,操作成功后 再往MQ发送消息。

即在 流程引擎 与 MQ 之间加一层判断,当 流程引擎操作成功后再往MQ发送消息。

调整前:
在这里插入图片描述
调整后:
在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风中思絮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值