最近在做一个简单审批流程的项目,由于只有固定二级审批所以没有工作流组件,然后就遇到一个审批节点捞单时候,多个人同时审批时候如何保证业务正常运行的问题,我采用的就是乐观锁来解决的。所谓捞单就是一个审批节点可以同时由多个人同时审批。
乐观锁意思是说多个事务修改数据库中同一条记录时候,并不是在一个事务中使用 for update 锁定这条记录从而防止其他事务在本事务提交前访问这条记录,而是在具体执行更新语句时候进行判断,并通过更新结果影响的行数来判断当前更新是否有效。具体来说有两种实现方式:
比如一个任务表里面包含如下字段:
id | comment | status |
---|---|---|
1 | 123456 | new |
一个任务的status有:new,operator,manager状态。new状态下有多个A人可以去更新这条记录的comment并且把status更新为operator,但是只能有一个人能成功。operator状态下可以多个B人去更新这题记录的comment并且status更新为manager但是只有一个人能更新成功。
这时候就可以使用status这个字段的值来实现乐观锁,具体来说: 对于A类人来说更新使用: update 表 set comment='',status='operator' where status = 'new' and id = 1; 对应B类型来说更新使用: update 表 set comment='',status='manager' where status = 'operator' and id = 1;
假如多个A类人同时去更新数据时候,第一个执行更新语句的人会锁住该条记录,更新status='operator",这时候其他事务是访问不了该记录的,直到当前事务提交返回结果1。当前事务提交后,然后其他事务在执行这条语句,这时候由于根据条件status = 'new' and id = 1获取到0条记录,所以返回0.所以如果更新结果返回1,则提示当前A类人数据更新成功,返回0的操作人则提示当前任务已经被捞单人员处理过了,无须在处理。同理B类人也是这样。
相比于2.1 要在任务表添加一个字段version,因为并不是所有业务场景都会有一个状态枚举值来做乐观控制
id | comment | status | version |
---|---|---|---|
1 | 123456 | new | 1 |
如图初始化版本号为1,这时候: 对于A类人来说更新使用: update 表 set comment='',status='operator',version=version+1 where version = 1 and id = 1; 对应B类型来说更新使用: update 表 set comment='',status='manager',version=version+1 where version = 2 and id = 1;
image.png
如图,一个合同基本信息对应多个审批任务
image.png
如图三级审批,假设三级审批都是捞单角色。只有三级都审批通过后合同基本信息的状态才是审批结束,只有一个审批节点的人审批驳回后,合同基本信息状态才是驳回状态,只有申请人撤回了申请,当前状态才是撤回。其他状态下都是审批中状态,也就是说即使一级,二级审批通过了,当前合同基本信息状态是审批中状态。
所以由于一级二级审批时候当前状态都是审批中,所以没办法用2.1的方式,所以使用version的方式。
__ 问题一__ 首先审批人都有自己的审批列表,对应一个审批任务来说,假如一级审批有两个人A和B,那么A和B打开自己的审批列表时候都会看到一个审批任务如下,都一个审批按钮,单击审批按钮就会进入审批页面
image.png
考虑A和B都看到了同一个审批任务,其中A单击了审批按钮,进入了审批页面,并且审批了该任务A任务状态从new->done,取消了其他捞单任务B的任务状态new->cancel。但是此时B的审批列表里面该任务还是处于审批状态,因为他没有刷新页面,假如这时候B单击审批时候如果不做任何处理将会出现问题,所以在进入审批页面时候还需要再次校验下B的任务当前状态是否还是new。
下面在说下A和B同时进入审批页面后,A审批后,那么B在审批如何正常处理。 考虑在A和B进入页面时候去合同基本信息里面根据id获取当前version然后把version加密后的值encversion存在前端审批页面,当审批时候在使用该version进行乐观锁控制。 update 表 set version=version+1,.... where id = *,version = encversion; 这样两个人同时审批时候只有一个人能审批成功。