锁
业务场景
针对一个赔付工单(由底下小二发起),当金额数量大于必定值之后,针对这笔工单就会有层层审批(风控),先YY一个审批流「TL审批」--->「主管审批」--->「财务审批」.这里就会存在3种权限「一审权限」「二审权限」「终审权限」,当这笔工单被小二提交之后就会给小二对应的TL建立一个审批任务,在主管的界面就能够看到相应的审批任务,主管能够点击经过或者拒绝数据库
实现
1.查询任务,判断当前角色是否有权限操做该笔任务,任务没有完结等一系列校验
2.驱动状态机更新工单状态
3.完结任务
异常场景
场景一
- 操做:主管疯狂点击经过按钮3次(前提是按钮点击一次不会灰显,就算灰显也能够经过模拟请求来实现)
- 异常状况:三个点击线程都运行完1,而后线程1驱动状态机(经过 + 当前状态:待TL审批)获得的结果是待主管审批,紧接着线程2驱动状态机(经过 + 当前状态:待主管审批)获得的结果是待财务审批,而后线程3再运行驱动状态机(经过 + 当前状态:待财务审批)获得的结果是出帐成功(不考虑屡次完结任务会出现异常)
- 异常分析:在该场景中,只要角色拥有「一审权限」就能够经过漏洞直接把该订单审核出帐
-
解决方案:线程
- 细化状态机中的每一个审核操做
1.查询任务,查询该笔任务对应当前操做类型(TL审批OR主管审批OR财务审批)
---这里不单单是「经过」操做,判断当前角色是否有对应操做权限
2.根据当前操做类型+当前状态驱动状态机
3.完结任务
- 在查询任务以前加一个全局锁,针对这笔工单进行全局锁定(更加优雅)
场景二
- 操做:一个角色同时拥有一审权限和二审权限,当他打开一个工单要进行一审,可是其它主管已经执行了一审的动做,而且更新了一些信息.由于该角色页面没有刷新获取不到更新的信息,而后点击了经过按钮
- 异常状况:点击经过按钮就至关于进行了二审,会形成该角色获取不到最新信息而产生误判
- 解决方案:在场景一增长一个全局锁的前提下,能够给页面传递一个工单
modifyTime
,在全局锁里面判断modifyTime
是否一致,若是不一致说明该笔工单已经被更新了,能够给用户相应的提醒
其它
- 在业务中整个状态机的流转都是肯定的,因此为了保证状态流转正确,因此在更新数据库状态的时候,须要带上关于状态的乐观锁
UPDATE XXX SET status = XXX WHERE id = XXX AND from_status = XXX
- 若是使用的是全局锁,那么每一个操做工单的地方都须要加上相应的全局锁