【テクニカル・上級編】DB2埋め込みSQLにおけるトランザクション制御(COMMIT/ROLLBACK) – PL/Iの基本構文とデータ制御実践ガイド

CICS/DB2環境におけるUOWの罠:SYNCPOINTとCOMMIT/ROLLBACKの同期制御を極める

メインフレームの現場で長くシステムアーキテクトをやっていると、オープン系から転身してきた優秀なエンジニアたちが「なぜメインフレームのトランザクション制御はこれほどまでに複雑なのか」と頭を抱えるシーンに幾度となく直面する。

特に、CICS(Customer Information Control System)という圧倒的な信頼性を誇るオンライン制御プログラムの下で、DB2の埋め込みSQLを叩くとき、論理作業単位(UOW:Unit of Work)の境界を見誤ると、データ不整合という名のパンドラの箱が開く。

今回は、PL/Iで書かれた基幹システムにおいて避けて通れない、CICSの`SYNCPOINT`コマンドとDB2のトランザクション制御(COMMIT/ROLLBACK)の同期挙動について、コンパイラやランタイムの裏側の動きまで踏み込んで徹底的に解説しよう。

—

1. 予約語を持たないPL/Iの自由度と、それに伴う「お作法」

本題に入る前に、PL/Iの根本的な言語特性に触れておきたい。CやJava、あるいはC#といったモダンな言語とは異なり、PL/Iには厳密な意味での「予約語(Reserved Words)」が存在しない。

例えば、`IF`や`THEN`、さらには今回解説するSQLのキーワードでさえも、コンテキストによっては変数名として定義できてしまう。
「じゃあ、コンパイラはどうやって識別子と命令を判別しているのか?」というと、文脈(Context)ベースの解析を行っている。そのため、コーディング規約を厳格に定めておかないと、プリプロセッサやコンパイラが意図しない解釈をし、不可解な挙動を引き起こす温床になる。

特にDB2の埋め込みSQL(`EXEC SQL`)やCICSコマンド(`EXEC CICS`)を混在させる場合、PL/Iの柔軟性は諸刃の剣となる。識別子の命名規則一つをとっても、トランザクションの境界を明確にするためのアーキテクチャ設計が不可欠なのだ。

—

2. CICS `SYNCPOINT` と DB2 `COMMIT` の二相コミット(2PC)のメカニズム

CICSオンライン環境下では、リソースマネージャ(CICS自身とDB2)の間でトランザクションの原子性(Atomicity)を保証するため、二相コミットメントプロトコル(2PC)が自動的に調停される。

ここで絶対に覚えておかなければならない鉄則がある。

> 「CICS環境下では、DB2の `EXEC SQL COMMIT` や `EXEC SQL ROLLBACK` を直接記述してはならない」

これをやってしまうと、CICSのタスク管理とDB2のリソース管理の間で同期が取れなくなれ、コンパイラやDB2プリコンパイラがエラーを吐くか、最悪の場合はランタイム異常終了(AICAやAD2ZAベンドなど)を引き起こす。

CICS環境におけるトランザクションの確定(コミット)および破棄(ロールバック)は、必ずCICSのコマンドを使用する。

  • 作業の確定: `EXEC CICS SYNCPOINT`
  • 作業の異常取消: `EXEC CICS SYNCPOINT ROLLBACK`

これらを実行すると、CICSは内部で同期点マネージャを動かし、VSAMなどのCICSリソースと、DB2データベースの双方に対して同時にコミットまたはロールバックを指示する。

—

3. 実践:PL/I & 埋め込みSQLにおけるUOW制御の実装パターン

百聞は一見に如かず。CICS配下で動作するPL/Iプログラムにおいて、正常時は同期点を取得し、異常検知時には安全にロールバックを行う実用的なコードパターンを見ていこう。

1
/ —————————————————- /
/ CICS / DB2 連携トランザクション制御サンプル /
/ —————————————————- /
TRANS_CONTROL_PROC: PROC(P_INPUT_DATA) OPTIONS(MAIN);

DCL P_INPUT_DATA CHAR(100) LOCAL;

/ ワーキングストレージ変数の定義 /
DCL WK_STATUS_CODE PIC ‘9999’ INIT(0);
DCL WK_ERROR_MSG CHAR(80);

/ 埋め込みSQL用ホスト変数 /
EXEC SQL INCLUDE SQLCA;

/ エラー発生時の共通ジャンプ先 /
ON ERROR BEGIN;
GOTO ERROR_HANDLER;
END;

/ 1. 業務データの更新処理(DB2) /
EXEC SQL
UPDATE ACCOUNT_TBL
SET BALANCE = BALANCE – 1000
WHERE ACCOUNT_ID = :P_INPUT_DATA;

IF SQLCODE ^= 0 THEN
/ SQLエラー検知時は強制的にロールバックへ /
SIGNAL ERROR;
END;

/ 2. CICS管理下の別リソース(例:TSキューへの書き込み) /
EXEC CICS WRITE QNAME(‘LOGQ’)
FROM(P_INPUT_DATA)
LENGTH(100)
RESP(WK_STATUS_CODE);

IF WK_STATUS_CODE ^= DFHRESP(NORMAL) THEN
SIGNAL ERROR;
END;

/ 3. 正常終了時の同期点取得(UOWの確定) /
/ ※DB2とCICSリソースが同時にコミットされる /
EXEC CICS SYNCPOINT;

RETURN;

ERROR_HANDLER:
/ 4. 異常発生時のロールバック(UOWの破棄) /
/ DB2の更新もTSキューの書き込みもすべて巻き戻される /
EXEC CICS SYNCPOINT ROLLBACK;

WK_ERROR_MSG = ‘TRANSACTION ABORTED DUE TO SYSTEM ERROR.’;
/ ログ出力やエラー応答処理をここに記述 /

RETURN;

END TRANS_CONTROL_PROC;

このコードのポイントは、`EXEC CICS SYNCPOINT` を発行するだけで、DB2側のカーソル状態のクローズやロック解放、更新データの確定がCICSによって一元管理される点だ。

—

4. アベンド(ABEND)発生時とダンプ解析の深層

もし、上記のコードブロックで `SIGNAL ERROR` を捕捉し損ねたり、PL/Iのランタイムエラー(例えば、パックデシマルデータ例外すうじの不整合による `S0C7` アベンドなど)が発生してタスクが異常終了した場合、何が起きるか?

CICSは異常終了を検知した瞬間、自動的に暗黙の `SYNCPOINT ROLLBACK` を実行する。 これにより、途中で途切れたUOWによるダーティリードや、片肺だけのデータ更新(DB2だけ更新されてVSAMが更新されていない状態)が防がれる。

現場でよくあるトラブル:パックデシマルの内部符号反転バグとダンプ

マイグレーション現場やレガシー保守で最も恐ろしいのが、外部から不正な文字データが混入した状態でパックデシマル(`PIC S9(n) COMP-3`)演算を行い、`ASRA`(CICSのS0C7相当)アベンドを引き起こすケースだ。

ダンプ(CEEDUMPやCICSトランザクションダンプ)を解析する際、以下の点に注目する必要がある。
1. PSW(Program Status Word)のアドレス: どのステートメントの、どの変数の演算で落ちたか。
2. WORKING-STORAGE領域のダンプ: 問題のホスト変数がどのような16進数(ゾーン/パック)を保持していたか。
3. SQLCAの內容: アベンド直前に発行されていたSQLの `SQLCODE` や `SQLERRMC`。

特に、JavaやC#などのモダン言語へマイグレーションする際、この「CICSが自動的にロールバックしてくれる安全ネット」の存在を忘れて、移行先のフレームワーク側でトランザクション境界(`@Transactional` など)の設計を誤るトラブルが後を絶たない。レガシー側の挙動を完全に理解していないと、移行後に「バッチやオンラインでデータが消える・重複する」という致命的な不具合を生むことになる。

—

5. マイグレーション(レガシー移行)アーキテクトへの提言

もしあなたが今、PL/Iで書かれた巨大なメインフレームシステムを、Java(Spring Boot)やC#(.NET Core)へ移行するプロジェクトの舵を取っているなら、以下の原則をチームに徹底してほしい。

1. UOWのスコープを明確にする
メインフレームの `SYNCPOINT` が持っている「リソースを跨いだ一括コミット/ロールバック」の概念を、移行先のマイクロサービスアーキテクチャや分散トランザクション(Sagaパターンなど)にどうマッピングするのか、設計の初期段階で定義し尽くすこと。
2. SQLの自動コミットモードに毒されない
オープン系のフレームワークはデフォルトで「自動コミット(Auto-Commit)」が有効になっていることが多い。これを意識せずに移植すると、一連の業務処理の途中で部分的なコミットが走り、データ不整合の温床となる。明示的なトランザクション境界の設定が必須である。

PL/Iの構文やCICS/DB2の連携は、一見すると古臭い技術に見えるかもしれない。しかし、そこには何十年もの商用利用に耐えてきた「絶対にデータを壊さない」ための先人たちの知恵と執念が詰まっている。

そのメカニズムの本質を理解せずして、真に堅牢なモダンシステムを構築することはできない。アーキテクトとしての誇りを持って、レガシーの深層を極め尽くそう。

タイトルとURLをコピーしました