You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SQLRPGLE中控制Commit和Rollback操作

SQLRPGLE事务提交(Commit)与回滚(Rollback)控制规范

前置配置校验

很多人写了一堆事务逻辑完全不生效,第一步先排查两个基础配置:

  • 编译SQLRPGLE程序时,提交控制级别不能选COMMIT(*NONE),要根据业务隔离需求选COMMIT(*CHG)、COMMIT(*CS)、COMMIT(*RR)等级别,选*NONE的话所有SQL操作会执行完自动提交,显式写的Commit/Rollback完全无效。
  • 所有参与事务的物理文件、逻辑文件必须挂接系统日志(Journal),未加日志的文件无法纳入事务管控,执行DML时会直接抛出SQLSTATE 57007类错误。
  • 不要混用RPG原生DML操作码(WRITE/UPDATE/DELETE等)和SQL语句做事务控制,原生操作默认不纳入SQL事务边界,要让原生操作走事务,必须在F表定义行加上COMMIT关键字。

事务边界核心原则

  • 事务要尽可能短,绝对不要在事务中间加用户交互、长耗时外部调用、等待输入这类操作,长事务会长时间持有记录锁,轻则拖慢系统性能,重则引发大面积死锁。
  • 一个事务内只放逻辑上强原子关联的操作,比如订单头写入、订单明细写入、库存扣减这三个必须同成同败,就放在同一个事务里,无关的查询、日志写入这类操作不要塞进事务。
  • 永远不要依赖程序正常结束的自动提交逻辑,必须显式编写Commit/Rollback分支,避免程序异常终止时出现半提交的脏数据。

标准事务实现逻辑

每执行完一条写操作(INSERT/UPDATE/DELETE),必须立刻检查SQL返回状态,不要等所有操作跑完再统一判断,出错第一时间回滚。不要用WHENEVER SQLERROR CONTINUE后跳过状态检查,这是漏回滚的最高发原因。
标准实现参考代码:

ctl-opt main(OrderTran) dftactgrp(*no) actgrp(*new) commit(*chg);

dcl-proc OrderTran;
  dcl-s sqlstate char(5);
  dcl-s affectRow int(10);
  dcl-s errCode int(5) inz(0);

  // 显式设置事务隔离级别为读提交,普通业务场景通用
  exec sql SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

  // 写入订单头
  exec sql INSERT INTO ORDERHDR (ORDER_ID, CUST_ID, CRT_TS, TOTAL_AMT)
           VALUES (:iOrderId, :iCustId, current timestamp, :iTotalAmt);
  if sqlstate <> '00000' and sqlstate <> '01000';
    errCode = 101;
    exec sql ROLLBACK;
    return errCode;
  endif;

  // 写入订单明细
  exec sql INSERT INTO ORDER_DTL (ORDER_ID, LINE_NO, PROD_ID, BUY_QTY, UNIT_PRICE)
           VALUES (:iOrderId, :iLineNo, :iProdId, :iBuyQty, :iUnitPrice);
  if sqlstate <> '00000' and sqlstate <> '01000';
    errCode = 102;
    exec sql ROLLBACK;
    return errCode;
  endif;

  // 扣减库存
  exec sql UPDATE INVENTORY SET STOCK_QTY = STOCK_QTY - :iBuyQty
           WHERE PROD_ID = :iProdId AND STOCK_QTY >= :iBuyQty;
  if sqlstate <> '00000' and sqlstate <> '01000';
    errCode = 103;
    exec sql ROLLBACK;
    return errCode;
  endif;
  // 校验库存扣减影响行数,避免库存不足时update 0行还正常提交
  exec sql GET DIAGNOSTICS :affectRow = ROW_COUNT;
  if affectRow = 0;
    errCode = 104;
    exec sql ROLLBACK;
    return errCode;
  endif;

  // 所有步骤校验通过,最终提交
  exec sql COMMIT;
  if sqlstate <> '00000';
    errCode = 105;
    exec sql ROLLBACK;
    return errCode;
  endif;

  return 0; // 事务执行成功返回0
end-proc;

常见踩坑规避

  • 批量操作不要单条提交:比如批量导入千条级数据,不要每插一条就Commit,按业务场景选100-500条的批次提交即可,单条提交会产生大量日志,性能会差一个数量级。
  • 跨程序调用注意事务隔离:同一个活动组(ACTGRP)下的所有程序共享同一个事务,被调用程序里写的Commit/Rollback会直接把当前程序未提交的操作一起提交/回滚,跨服务调用优先给程序分配独立活动组,避免事务互相干扰。
  • 保存点(SAVEPOINT)不能替代全量回滚:回滚到指定保存点不会结束当前事务,只有最终执行Commit/Rollback才会真正关闭事务、释放锁。
  • 非必要不要用COMMIT HOLD/ROLLBACK HOLD:带HOLD参数的提交/回滚会在操作完成后继续持有记录锁,普通业务场景用无HOLD版本即可,避免不必要的锁占用引发等待。
  • 异常兜底逻辑不用额外开发:如果程序遇到断电、作业被强制结束这类极端异常,IBM i操作系统会自动回滚该作业下所有未提交的事务,不会出现脏数据,前提是你没有在错误分支做半提交操作。

内容的提问来源于stack exchange,提问作者Kunal Roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:48:26