スケーラブルデータベースサーバ HiRDB Version 8 UAP開発ガイド
採番業務では次の2種類の方法で採番できます。
ここでは,WITHOUT ROLLBACKオプション指定の表での採番について説明します。自動採番機能については,「4.19 自動採番機能」を参照してください。
実際の業務では,伝票番号や書類の番号の管理など,様々な採番業務があります。採番業務では,あるユーザが伝票番号を取得しようとしたとき,それと同時に他ユーザも伝票番号を取得しようとするケースが考えられます。
また,あるユーザが伝票番号を取得しようとしたときには,ほかのユーザが以前に取得した伝票番号と重複しないように,番号をカウントアップしておく必要があります。
このようなケースでは,あるユーザが伝票番号の取得処理中に,他ユーザが待ち状態になる可能性があります。このようなことを考慮し,HiRDBでは,排他待ちの影響を少なくして,採番業務をするための機能を提供しています。
採番業務を効率良く実施するため,排他待ちの影響が少なくなるように表を設計する必要があります。採番を管理する表への排他の影響を少なくするために,トランザクションのコミットを待たないで表への更新(追加,削除を含む)処理が完了した時点で,その行への排他を解除し,それ以降はロールバックされなくなるという機能を提供しています。この機能を実現するためには,表の設計者が,表定義時にCREATE TABLEのWITHOUT ROLLBACKオプションを指定する必要があります。
表定義時にWITHOUT ROLLBACKオプションを指定すると,行を更新した時点でロールバックされなくなります。このため,UAPやHiRDBシステムが異常終了した場合には,HiRDBシステムの再開始時に取得した番号を使用した業務の表に対しては正しくロールバックされ,整合性が保たれますが,採番管理表を更新する処理のどの時点までロールバックされたかが分かりません。このような場合,採番はしたが,その番号が業務で使用されなくなったりします。したがって,欠番が発生すると困るような業務には適していません。番号が連続でなくてもよい場合に適用するようにしてください。
採番を管理する表の例を次の図に示します。
図4-7 採番を管理する表の例
採番業務のアプリケーションプログラムの例を次に示します。なお,採番管理表と業務表を操作するアプリケーションプログラムは同一トランザクションを想定します。
(例)
伝票番号と書類番号を管理する採番管理表があるものとします。採番管理表から,最新の伝票番号を取得し,それを業務で使用するSQLの例を次に示します。
INSERT INTO 採番管理表 VALUE('伝票番号',1) ....1
:
DECLARE CUR1 CURSOR FOR .......................2
SELECT 採番 FROM 採番管理表
WHERE 種類='伝票番号' FOR UPDATE OF 採番
OPEN CUR1 .....................................3
FETCH CUR1 INTO :x_採番 .......................4
UPDATE 採番管理表 SET 採番=:x_採番+1 ..........5
WHERE CURRENT OF CUR1
CLOSE CUR1 ....................................6
:
取得した番号を利用した業務表へのアクセス処理 ..7
:
なお,採番ごとに3〜7を繰り返します。
WITHOUT ROLLBACKオプションを指定した表に複数の行を格納する場合,その表にインデクスを定義していないときは,すべての行が検索対象となるため,すべての行に対して一時的に排他が掛かります。このような場合,例えば,伝票番号の採番処理と書類番号の採番処理との間で,排他待ちになることがあります。これを回避するためには,クライアント環境定義のPDLOCKSKIPにYESを指定して,無排他条件判定をする必要があります。無排他条件判定をした場合には,検索処理時には排他を掛けないで,探索条件を満たした行に対してだけ排他を掛けます。
複数種類の採番を扱う場合,1回のSQLで複数行を更新するような処理はしないでください。排他の解除,及びロールバックがされなくなるタイミングが各行単位に,それぞれの行の更新処理が完了した時点となります。そのため,複数行を更新するUAPが異常終了すると,一部の行の更新がロールバックされない場合があります。
採番業務では,ある決まったパターンで処理することが多いため,その処理をストアドプロシジャとして登録しておくと便利です。
表の定義例,ストアドプロシジャの例を例1〜例3に示します。
CREATE FIX TABLE
owner_id.sequence_tbl(sequence_no INTEGER NOT NULL)
WITHOUT ROLLBACK; .......................................1
CREATE PROCEDURE owner_id.nextval(OUT next_no INTEGER)
BEGIN
DECLARE update_no INTEGER; ..............................2
DECLARE cr1 CURSOR FOR
SELECT sequence_no FROM owner_id.sequence_tbl
FOR UPDATE;
OPEN cr1;
FETCH cr1 INTO update_no; ...............................3
SET next_no=update_no; ..................................4
UPDATE owner_id.sequence_tbl SET sequence_no=update_no+1
WHERE CURRENT OF cr1; .................................5
CLOSE cr1; ..............................................3
END .......................................................2
COMMIT WORK; ................................................6
INSERT INTO owner_id.sequence_tbl(sequence_no) VALUES(1); ...7
COMMIT WORK; ................................................8
<順序番号の割り当て> ........................................9
CALL owner_id.nextval(OUT:xnext_no);
:
割り当てた順序番号xnext_noを使用した処理
:
CALL owner_id.nextval(OUT:xnext_no);
:
CREATE FIX TABLE
owner_id.sequence_tbl(sequence_key CHAR(30) NOT NULL,
sequence_no INTEGER NOT NULL)
WITHOUT ROLLBACK; ..........................................1
CREATE PROCEDURE owner_id.nextval(IN input_key CHAR(30),
OUT next_no INTEGER)
BEGIN
DECLARE update_no INTEGER; .................................2
DECLARE cr1 CURSOR FOR
SELECT sequence_no FROM owner_id.sequence_tbl
WHERE sequence_key=input_key FOR UPDATE OF sequence_no;
OPEN cr1;
FETCH cr1 INTO update_no; ..................................3
SET next_no=update_no; .....................................4
UPDATE owner_id.sequence_tbl SET sequence_no=update_no+1
WHERE CURRENT OF cr1; ....................................5
CLOSE cr1; .................................................3
END ..........................................................2
COMMIT WORK; ...................................................6
INSERT INTO owner_id.sequence_tbl(sequence_key,sequence_no)
VALUES('key_value_1',1); ...................................7
COMMIT WORK; ...................................................8
INSERT INTO owner_id.sequence_tbl(sequence_key,sequence_no)
VALUES('key_value_2',1); ...................................7
COMMIT WORK; ...................................................8
:
(順序番号の種類数分,初期値の行を挿入します)
<'key_value_1'の順序番号の割り当て> ............................9
xinput_key <-- 'key_value_1'
CALL owner_id.nextval(IN:xinput_key,OUT:xnext_no);
:
'key_value_1'に対して割り当てた順序番号xnext_noを使用した処理
:
xinput_key <-- 'key_value_1'
CALL owner_id.nextval(IN:xinput_key,OUT:xnext_no);
:
<'key_value_2'の順序番号の割り当て> ............................9
xinput_key <-- 'key_value_2'
CALL owner_id.nextval(IN :xinput_key,OUT:xnext_no);
:
'key_value_2'に対して割り当てた順序番号xnext_noを使用した処理
:
xinput_key <-- 'key_value_2'
CALL owner_id.nextval(IN:xinput_key,OUT:xnext_no);
:
CREATE FIX TABLE
owner_id.sequence_tbl(sequence_no INTEGER NOT NULL)
WITHOUT ROLLBACK; .........................................1
CREATE PROCEDURE owner_id.nextval(OUT next_no INTEGER)
BEGIN
DECLARE update_no INTEGER; .................................2
DECLARE cr1 CURSOR FOR
SELECT sequence_no FROM owner_id.sequence_tbl FOR UPDATE;
OPEN cr1;
FETCH cr1 INTO update_no; ..................................3
SET next_no=update_no; .....................................4
IF update_no=2147483647 THEN
SET update_no=-2147483648;
ELSE
SET update_no=update_no+1;
END IF; ....................................................5
UPDATE owner_id.sequence_tbl SET sequence_no=update_no
WHERE CURRENT OF cr1; ....................................6
CLOSE cr1; .................................................3
END ..........................................................2
COMMIT WORK; ...................................................7
INSERT INTO owner_id.sequence_tbl(sequence_no)VALUES(1); .......8
COMMIT WORK; ...................................................9
<順序番号の割り当て> ...........................................10
CALL owner_id.nextval(OUT:xnext_no);
:
割り当てた順序番号xnext_noを使用した処理
:
CALL owner_id.nextval(OUT:xnext_no);
:
All Rights Reserved. Copyright (C) 2006, 2016, Hitachi, Ltd.