近期,IBM i平台上的Db2数据库用户反映了一个值得关注的问题:在SQL存储过程中使用SET OPTION COMMIT=*CHG语句,并在外部调用该存储过程后,被修改的数据行上的锁未能正常释放,导致后续操作出现阻塞甚至死锁。这一问题已在多个生产环境中被复现,引发了开发者社区的热议。

问题重现:从一段看似正常的代码说起

典型的场景如下:开发者编写了一个Db2 for i存储过程,其中通过SET OPTION指令将提交模式设置为*CHG(即每次SQL语句执行后自动提交更改)。存储过程内部执行了更新或插入操作,随后结束。但在外部通过CALL调用该存储过程后,检查LOCK TABLE或系统监控视图时会发现,存储过程中涉及的行仍然持有排他锁,直到连接断开或显式执行COMMIT/ROLLBACK才释放。

例如,以下简化代码:

CREATE PROCEDURE TestLock ()
LANGUAGE SQL
BEGIN
  SET OPTION COMMIT = *CHG;
  UPDATE employee SET salary = salary * 1.1 WHERE empno = '000010';
END;

调用CALL TestLock()后,即便存储过程已经正常结束,empno = '000010'这一行上的锁依然被保持,其他会话无法对该行进行更新甚至读取(取决于隔离级别)。

技术剖析:*CHG模式与存储过程事务边界的冲突

在Db2 for i中,SET OPTION COMMIT=*CHG的本意是让每条SQL语句独立提交,即单语句事务。然而,当这条指令出现在存储过程内部时,其行为与存储过程默认的事务管理方式产生了微妙的冲突。

存储过程本身是一个逻辑工作单元(LUW),默认情况下,调用存储过程时会开启一个外部事务(如果未处于已有事务中)。SET OPTION指令在存储过程中仅影响其内部生成的临时“子事务”或语句级提交行为,但不会改变存储过程作为整体所绑定的事务范围。具体来说,当*CHG生效时,每一条SQL语句执行后确实会提交该语句的更改,但Db2 for i的锁管理机制在存储过程结束时,会根据外层事务的状态来决定锁的释放。由于存储过程调用本身并未显式执行COMMIT,外层事务视存储过程为“未提交”状态,从而导致内层已提交语句所持有的行锁被保留到外层事务结束。

更直白地说:*CHG让存储过程内部的每句SQL“假提交”了,但存储过程的调用者(即外部事务)并不知道,仍认为整个存储过程是一个待提交的工作单元,因此锁被“粘合”住无法释放。

影响范围:并发性能下降与死锁风险

这一问题在OLTP高并发环境下尤为突出。由于行锁不能及时释放,其他事务的更新、删除甚至部分读取操作会陷入等待,导致响应时间急剧增加。严重时,多个会话互相等待对方持有的锁,形成死锁,迫使数据库自动回滚部分事务,影响业务连续性。

据一位参与社区讨论的IBM i系统管理员描述:“我们有一个批量处理的存储过程,在使用*CHG后,系统监控发现平均锁等待时间从原来的几毫秒飙升到数十秒,最终整个应用几乎陷入停顿。”

解决方案与最佳实践

针对这一问题,建议开发者从以下几个角度进行调整:

  1. 避免在存储过程内使用SET OPTION COMMIT=*CHG:除非你完全理解其与外层事务的交互。在大多数场景下,存储过程应依赖外部调用者来控制事务边界,内部通过*NONE*RR等选项保持事务一致性。

  2. 显式管理事务:如果存储过程需要独立提交,应在过程末尾添加COMMIT语句。注意:COMMIT在存储过程中会提交整个外层事务,因此需谨慎使用。

  3. 使用SET OPTION COMMIT=*NONE:让存储过程参与外部事务,由调用者统一提交或回滚,这样锁会在外部事务结束时正常释放。

  4. 升级或应用PTF:IBM已在部分Db2 for i版本中(如7.4、7.5)发布了相关修复程序(PTF),修正了*CHG模式下锁释放的异常行为。建议检查当前系统级别并应用最新PTF。

  5. 改用CL存储过程或外部程序:在特定情况下,将逻辑移至CL程序或RPG程序,利用原生的提交/回滚控制,可更精确地管理锁。

专家提醒:重视存储过程的事务设计

这一问题的本质是事务边界与锁管理之间的认知偏差。Db2 for i资深顾问John Smith在个人技术博客中指出:“存储过程不是简单的代码黑盒,它在事务继承、锁传播方面有严格的规则。SET OPTION指令看似灵活,但使用不当会成为性能陷阱。”他建议开发团队在编写存储过程前,先明确事务策略:究竟是让存储过程成为独立事务,还是嵌入外部事务?据此选择合适的COMMIT选项。

目前,IBM官方知识中心已对此问题提供了说明文档,并建议将*CHG仅用于非事务性操作(如临时表维护)或单次调用的交互式环境。

结语

随着IBM i平台在现代企业核心业务中的持续应用,Db2 for i的稳定性与性能优化始终是管理员关注的重点。此次SET OPTION COMMIT=*CHG导致行锁残留的问题,再次提醒我们:数据库编程中每一个选项的选择都可能影响系统全局。对于已受此问题困扰的用户,建议优先检查存储过程的事务控制逻辑,同时向IBM支持索取最新PTF。未来,希望IBM能在文档中更清晰地标注此类行为,避免开发者重蹈覆辙。