一、先看bug
在 (三)springboot2.7.6集成activit5.23.0之流程跟踪高亮表现 末端就发现高亮表现与预期不一样,比如上面的任务2前面的箭头没有高亮表现。
二、分析原因
详细分析步骤省略了,告急是ProcessInstanceHighlightsResource类中有段代码有bug。
可以看到源码本身有解释,说按开始时间排序不精确,用默认排序是精确的。
select * from `act_hi_actinst`
我们可以去数据库中查询活动列表,希望按活动发生的先后顺序排序。可以发现,大部门时候,按活动的开始时间排序是精确的,但是在活动体系自动完成或者说几个活动在毫秒级时间内同时完成,这个时候无法通过开始时间判断活动发生的先后顺序。所以官方源码中解释了按开始时间排序。
背面另有一个按活动id排序,这个也是不对的,活动id在流程摆设时就确定了,与流程实例中的活动顺序无关。
那解释上为什么说按默认排序是精确的呢?
我的理解是当默认排序是以活动记录的插入顺序排序时,就是精确的。
但实际情况默认排序并不一定总是活动记录的插入顺序排序的。不一定总是精确。
MySQL的默认排序规则:
1.如果查询条件无索引列,默认按主键正序排序。
2.查询条件中有索引列,默认顺序为:主键 > 唯一索引 > 普通索引,如果在SQL中查询条件同时存在有多个,那么按照索引最先创建的顺序进行正序排序。
例:SELECT * FROM a WHERE a.id = ‘a’ and a.user_id = ‘a’;
如果id和user_id都是索引,id先创建,则按照id进行正序排序。
从上面截图,我们就可以看到,默认排序并没有按插入顺序排序。告急原因是ID_是字符串类型,而不是整数类型,所以升序就是上图的结果。
综上,高亮表现BUG的原因是查询活动列表时没有按活动的先后顺序排序。
三、修复方案
找出原因后,就可以针对性的进行修复。详细上面的问题,可以有2种方案。
(方案一)使用mysql的默认排序规则。
这种方案,这则是使用activiti的ID天生器实现,默认的ID天生器实现就不详细分析了,看上面的截图大概也差不多可以推测出来。只要将ID天生器替换为严酷按递增顺序天生的就可以了。
下面先容几种的ID天生方法:
- UUID:天生的UUID是由 8-4-4-4-12格式的数据组成,其中32个字符和4个连字符' - ',一般我们使用的时候会将连字符删除 uuid.toString().replaceAll("-","")。该算法不是递增的,不能满意要求。
- StrongUuidGenerator:activiti自带的ID天生器。但是天生的ID不是递增的。
- 数据库天生:ID_字段类型是字符串,所以无法使用自增字段。如果要改为整数自增字段,引擎改动太复杂,后过不可控,排除。
- 雪花算法-Snowflake:该方法比力适配。但他也有相应的缺点:依赖体系时钟,64位字符串占空间,不实用短时间天生大量的ID。
- 百度-UidGenerator:不是很认识,没用过。
- 美团Leaf:不是很认识,没用过。
所以该方案,只要把ID天生器换成雪花算法就可以了。但要注意避免雪花算法天生重复ID。
1.雪花算法实现SnowflakeIdWorker.java
2.自定义ID天生器
SnowflakeIdWorkerGenerator.java
- package org.activiti.engine.impl.ext;
- import org.activiti.engine.impl.cfg.IdGenerator;
- import xpl.util.id.SnowflakeIdWorker;
- public class SnowflakeIdWorkerGenerator implements IdGenerator {
- @Override
- public String getNextId() {
- return ""+SnowflakeIdWorker.nextId();
- }
- }
复制代码 3.替换activiti默认的ID天生器
这个替换研究了好一会,才找到替换的方法。
所以需要扩展引擎配置,只需要实现ProcessEngineConfigurationConfigurer接口就可以了。
于是,我们创建MyProcessEngineConfigurationConfigurer类。代码如下:
- package xpl.study.activiti;
- import org.activiti.engine.impl.ext.SnowflakeIdWorkerGenerator;
- import org.activiti.spring.SpringProcessEngineConfiguration;
- import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
- import org.springframework.context.annotation.Configuration;
- @Configuration
- public class MyProcessEngineConfigurationConfigurer implements ProcessEngineConfigurationConfigurer{
- @Override
- public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
- processEngineConfiguration.setIdGenerator(new SnowflakeIdWorkerGenerator());
- }
- }
复制代码 4.运行测试
(方案二)使用order by与实现按活动发生顺序进行排序。
1.对act_hi_actinst表新增一个排序字段,而且自增。
2.修改源码HistoricActivityInstanceQuery,新增一个接口orderBySeq。
- package org.activiti.engine.history;
- import org.activiti.engine.query.Query;
- /**
- * Programmatic querying for {@link HistoricActivityInstance}s.
- *
- * @author Tom Baeyens
- * @author Joram Barrez
- */
- public interface HistoricActivityInstanceQuery extends Query<HistoricActivityInstanceQuery, HistoricActivityInstance>{
- //...........
-
- HistoricActivityInstanceQuery orderBySeq();
-
- }
复制代码 3.修改源码HistoricActivityInstanceQueryImpl,新增orderBySeq实现
- public HistoricActivityInstanceQuery orderBySeq() {
- orderBy(HistoricActivityInstanceQueryProperty.SEQ);
- return this;
- }
复制代码 4.修改源码HistoricActivityInstanceQueryProperty ,新增一个静态变量。
- public static final HistoricActivityInstanceQueryProperty SEQ = new HistoricActivityInstanceQueryProperty("SEQ_");
复制代码 5.修改源码ProcessInstanceHighlightsResource ,查询时拼接seq字段参与排序。
6.运行测试
方案二实在还可以更简单的实现。第一步与上面一样,但是可以省略上面2,3,4步,直接到第5步,使用createNativeHistoricActivityInstanceQuery查询列表,就可以直接跳过2,3,4步实现了。
四、总结
颠末测试二种方案都是可行。个人比力倾向于第二种。第二种比力有安全感,第一种如果服务器时间回拨,大概导致ID重复,体系故障。固然发生几率不是很大,但如果对体系稳定性要求较高的话照旧存在一些风险。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |