近日,发现某生产系统中使用基础框架所引入的Activiti 5.21.0版本中,HistoricTaskInstanceQuery的count方法存在缺陷(其他的count有没有缺陷没有细看),表现为HistoricTaskInstanceQuery的listPage和count得到的结果差异巨大,且count的结果明显不正确:
上述代码的pattern在产品系统中被大量用到,即通过listPage和count向前台返回分页查询的结果及总记录数,供前台展示及后续分页。
此前,HistoricTaskInstanceQuery的查询条件相对简单,并未发现任何问题;而当针对某个新需求,增加了针对流程实例变量、包含OR等复杂查询条件后,就暴露出了上述的问题。显然,count的结果明显是诡异的(实际结果总数量为21条、count的结果错误,整个任务历史表才2000条数据)。搜遍全网无结果,无奈看源码,发现确实有BUG。
开启Activiti日志,可以观察到listPage和count对应的实际查询语句:
前者为DB2的分页查询写法。可见,HistoricTaskInstanceQuery拼接查询条件是通过多个LEFT JOIN实现的,除了DB2的分页逻辑外,这两个查询的核心逻辑基本是一样的,唯独在COUNT中缺少了应有的DISTINCT谓词,手拼SQL后验证确实如此。观察源码的实现:
最终调用到了HistoricTaskInstance.xml中:
接下来确认该缺陷的影响范围。经查,目前Activiti最新版本7.x中已经修复了该问题,其解决方法恰恰是增加了DISTINCT。我们可以在GitHub的repo中确认:
显然,当存在复杂查询拼接出的LEFT JOIN时,DISTINCT是不可以少的。但还是有某些无知的小白竟然想通过删除DISTINCT来提高查询效率:
5.22.0是Activiti 5.x的最高版本,根据Release Note显示也没有修复该问题;而查看5.22.0的源码也确实没有解决该问题。尽管最新7.x的Activiti已经修复了该问题,但在GitHub中翻了半天也没有翻到到底是在哪个版本中修复的这个问题,翻了下Release Note也没有翻到,那就管不了这么多了。
由于目前生产系统中已经有大量的数据,贸然提高Activiti大版本需要执行upgrade脚本,而又难以在测试环境验证upgrade脚本的正确性,因此不能通过简单升级Activiti版本的方式来解决这个问题。退而求其次,由于只需要修改有问题的Mapper文件,因此我们可以直接修改activiti-engine-5.21.0.jar中的HistoricTaskInstance.xml及pom.xml,构造一个activiti-engine-5.21.1.jar并上传至私有Maven仓库中即可。
转载时请保留出处,违法转载追究到底:进城务工人员小梅 » Activiti 5.x HistoricTaskInstanceQuery的count方法缺陷