3. 并发冲突的典型场景
在审批流系统中,并发冲突并非理论假设,而是高并发业务下的常态。当多个审批人同时操作同一审批节点时,数据库事务隔离级别与业务逻辑之间的缝隙会被瞬间放大。本章聚焦三种最典型的冲突场景,分析其发生机理与数据异常表现。
3.1 场景一:多人同时审批同一单据
这是最基础的并发冲突场景。当审批流流转至某一节点,且该节点配置为“多人会签”或“任意一人通过即可”时,多个审批人几乎同时点击“通过”按钮,系统在缺乏乐观锁或悲观锁保护的情况下,会出现以下数据异常:
| 异常类型 | 现象描述 | 业务后果 |
|---|---|---|
| 重复提交 | 同一单据生成多条审批记录,状态被多次更新 | 下游系统收到重复通知,触发重复发货、重复付款 |
| 状态覆盖 | 后提交的审批结果覆盖前一个结果,导致通过/驳回状态丢失 | 审批结论与操作日志不一致,审计追溯失败 |
| 版本丢失 | 基于旧版本数据提交,导致最新审批意见被丢弃 | 关键审批意见丢失,业务决策依据不完整 |
典型错误案例: 采购订单审批节点,A审批人于10:00:00读取单据状态为“待审批”,B审批人于10:00:01也读取到“待审批”。A于10:00:02提交通过,B于10:00:03提交通过。若未加锁,B的提交会基于旧版本覆盖A的结果,最终状态仍为“待审批”或产生两条通过记录。
3.2 场景二:多人同时修改审批意见
在审批过程中,审批人不仅需要做出“通过/驳回”决策,还经常需要填写审批意见、修改金额、调整日期等业务字段。当多人同时修改同一单据的审批意见时,会产生“写偏”冲突:
- 写偏(Write Skew):每个审批人读取的数据集不同,各自修改不同的字段,但整体上破坏了业务约束。例如,A修改“审批金额”为100万,B修改“审批意见”为“同意”,但两人均未察觉对方修改,最终单据同时包含两个不一致的修改。
- 丢失更新(Lost Update):后提交的审批意见完全覆盖前一个意见,导致前一个审批人的意见彻底丢失。这在需要保留完整审批链的业务场景中尤为致命。
- 约束违反(Constraint Violation):例如,审批规则要求“金额超过50万必须由两人同时同意”,但A和B同时提交通过,数据库层面未检测到约束,导致违规通过。
设计建议: 对于审批意见修改场景,推荐使用“字段级乐观锁”或“JSON合并策略”,而非简单的行级锁。字段级乐观锁可以精确控制每个字段的版本,避免因一个字段的修改而阻塞整个单据。
3.3 场景三:多人同时驳回与通过
这是最复杂的冲突场景,因为“驳回”和“通过”在业务语义上是互斥的,但在并发执行时,数据库层面可能同时接受这两种操作。具体表现为:
| 并发操作组合 | 数据库行为 | 业务语义错误 |
|---|---|---|
| A通过 + B通过 | 两次更新,后一次覆盖前一次 | 状态正确,但产生重复审批记录 |
| A通过 + B驳回 | 两次更新,后一次覆盖前一次 | 最终状态取决于谁后提交,与业务规则矛盾 |
| A驳回 + B驳回 | 两次更新,后一次覆盖前一次 | 状态正确,但驳回原因可能被覆盖 |
| A通过 + B驳回(同时) | 数据库死锁或更新丢失 | 单据状态不确定,需要人工介入 |
风险提示: 在“任意一人通过即可”的审批节点中,若A通过的同时B驳回,且B的提交晚于A,则单据最终状态为“驳回”,但A已经触发了下游流程(如通知发货)。这种“状态回退”会导致业务数据不一致,且难以自动修复。
3.4 并发冲突的SVG架构图
下图展示了三种典型并发冲突在审批流系统中的数据流与冲突点:
3.5 冲突场景对比总结
下表从冲突类型、发生阶段、影响范围三个维度对三种典型场景进行对比:
| 场景 | 冲突类型 | 发生阶段 | 影响范围 | 典型后果 |
|---|---|---|---|---|
| 多人同时审批同一单据 | 丢失更新、重复提交 | 审批提交阶段 | 单条审批记录 | 重复通知、状态丢失 |
| 多人同时修改审批意见 | 写偏、字段覆盖 | 意见编辑阶段 | 多个业务字段 | 审批意见不一致、约束违反 |
| 多人同时驳回与通过 | 状态覆盖、语义冲突 | 审批决策阶段 | 整条审批流 | 状态回退、下游流程异常 |
核心认知: 三种场景的本质都是“读取-检查-写入”的竞态条件。解决思路包括:使用乐观锁(版本号/时间戳)、悲观锁(行锁/表锁)、分布式锁(Redis/ ZooKeeper),以及业务层面的幂等设计与最终一致性补偿。下一章将详细分析这些解决方案的选型与实现。