锁
业务场景
针对一个赔付工单(由底下小二发起),当金额数量大于一定值以后,针对这笔工单就会有层层审批(风控),先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
- 如果使用的是全局锁,那么每个操作工单的地方都需要加上相应的全局锁
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。