1.问题描述:
反馈,用户提交待办后,流程图中的状态没有改变
2.分析原因:
状态由数据库中待办的状态所决定,查明数据库,代办的状态为未提交,状态错误。
(此类问题由多线程访问冲突所致,无法进行问题重现。)
查日志:
查到的相关日志结果:
1.acviti报的Exception:can not find taskId
2.有一个请求(线程)成功执行了待办提交这个操作,
3.提示重复提交请求
4..update 。。。。set status = 0 。。。。。超时,
这条SQL语句更改的就是当前发生错误的待办,这条语句正是将待办状态改为未提交的罪魁祸首。
在查日志前,分析可能发生异常导致数据库回滚所致。但是当得知上面三条现象时,回滚就可以排除了。因为整个提交都是事务性的,但是,数据库并没有回滚的迹象,准确来说并不是所有的请求都回滚了。
此时开始关注线程竞争的情况(分析了用Redis实现锁的机制);
刚开始关注多线程竞争情况的时候,只是关注提交待办这个接口的竞争,后来证明是不全面,理由有二,一是对代码不够熟悉,二是,先入为主的思想
按时间发生的顺序,体现到数据库的顺序,按线程确定每一个请求的状况:
当提交待办是,多次提交(网络有延迟),后面的等待锁,等到等获取到锁匙,activiti提交待办时,会找不到对应的taskId,因为此task已经被执行了,所以会发生can not find taskId异常。
根据日志提示分析保存待办的接口(此前一直认为这是service层的方法),它进行的操作就是保存待办参数,更新job一些参数,这里把status更新为0(这不是一个功能,只是默认值,为了重用提交待办的代码)。
这里的保存待办,发生了慢查询,等待锁20多s。
根据提交待办,保存待办,二者的顺序发生了逆转,提交待办后,保存待办又将状态改为了0,导致待办状态没有改变的假象。
线程运行模拟图: