排他制御(テーブルロック)の方法
内容
テーブル項目を使っている時に、テーブルをロックして他のユーザが利用出来なく
(しばらく待ち状態)にして、処理が終わったら解放する。
良く使うのが、「採番」処理の時です。受付番号や受注番号、注文番号等
絶対に重複した番号を取らない様にする場合などに排他制御を使った処理を行います。
#排他制御 #ロック #lock
動作内容(イメージ)
ほぼ同時にアクセスした場合、どちらかが優先して処理します。
一時待機状態。優先した方は、採番(sqno)へ +1加算処理して結果を返します。
片方の処理が終わる(comit)と待機していた方が、採番処理を実行します。
テーブルの準備
採番用のテーブルを準備します。
※PTW(PowerBuilder TotalWorkSystem)を使うと簡単にテーブルも生成します。
テーブル生成
PTW(PowerBuilder TotalWorkSystem) カラム(項目)設定画面
SQL文生成
CREATE TABLE PTW.AUTO_NO (
SQNO NUMBER ( 6,0 ));
/************* 主キー UNIQUE INDEX定義 ************/
CREATE UNIQUE INDEX PTW.AUTO_NOs1_key ON PTW.AUTO_NO ( SQNO );
/************* 外部キー INDEX定義 1から15最大************/
/************* SYNONYM定義 ************/
CREATE PUBLIC SYNONYM AUTO_NO FOR PTW.AUTO_NO ;
oracle sql*plusでテーブルを生成
排他制御プログラム
PowerBuilderデータベーステーブル情報
PTWで生成された採番テーブル(Auto_No)
初回テーブルにレコードが無いので1レコードを挿入して初期値ZEROをセットします。
採番排他処理実行画面
自動採番1と自動採番2は、そけぞれ排他制御プログラムが異なります。
どちらも機能は同じなので扱いやすい方を利用すると良いでしょう。
自動採番1プログラム
// 排他制御、番号を自動採番して重複しない様にします。
// 複数のPCから同時に採番した場合LOCKを掛けて(排他制御)採番します。
// 主に受付番号や注文番号など主キーとして採番するのに利用します。
// COMMITされるまでLOCK状態になります。
//
// 採番用のテーブルを準備します。
// スキーマ :PTW
// テーブル名:AUTO_NO
// 項目名 :SQNO
String SqlCode
SQLCODE="LOCK TABLE PTW.AUTO_NO IN Exclusive Mode"
EXECUTE IMMEDIATE :SqlCode ;
if SQLCA.SQLCODE < 0 then
MessageBox("排他制御エラー", "自動採番テーブル排他制御エラー:" + SQLCA.SQLErrText)
RETURN
end if
DECLARE CURSOL Cursor FOR
SELECT "PTW"."AUTO_NO"."SQNO"
FROM "PTW"."AUTO_NO" USING SQLCA;
String W_SQNO
OPEN CURSOL;
FETCH CURSOL
INTO :W_SQNO;
CLOSE CURSOL;
//Fetch Error確認
if SQLCA.SQLCode = -1 then
MessageBox("SQNO:呼出しエラー:",SQLCA.SQLErrText,Information!)
HALT
end if
//
//W_SQNO自動採番の加算カウンター更新作業
Double AoutUKEban //数値宣言//
String AoutUKEbub_C //文字宣言//
Double ULengs //自動採番の加算桁数算出
Double J
String ZER=""
//
AoutUKEban=Double(W_SQNO)+1 // 採番号+1(加算)
AoutUKEbub_C=String(AoutUKEban) // 文字データに変換
//MESSAGEBOX("W_SQNO","加算"+AoutUKEbub_C)
//
ZER = ""
ULengs= 5 - len(AoutUKEbub_C) // 実受番桁数は4桁 0001~9999まで、加算桁数算出
For J=1 To ULengs // 5桁に見合う分の前0を付加する
ZER = ZER + "0"
Next
//
AoutUKEbub_C = ZER + AoutUKEbub_C //前0付加分の自動受番(5桁分)
if AoutUKEbub_C = "100000" then //採番11桁防止
AoutUKEbub_C = "00001"
end if
//MESSAGEBOX("WS_SQNOマスター","5桁 "+AoutUKEbub_C + "|" + STRING(AoutUKEban))
//UPDATE採番更新
Dec w_sq
w_sq = Dec(AoutUKEbub_C)
UPDATE "PTW"."AUTO_NO"
SET "SQNO" = :w_sq USING SQLCA ;
//
IF SQLCA.SQLNRows = 0 then
MessageBox("採番書込みエラー(SQLNRows=0)","SQNO更新できませんでした。" + SQLCA.SQLErrText, Exclamation!)
ROLLBACK ;
RETURN
END IF
//MessageBOX("","|"+string(w_sq)+"|")
// 採番セット
em_pno.text = string(w_sq)
COMMIT;
自動採番2プログラム
// 排他制御、番号を自動採番して重複しない様にします。
// 複数のPCから同時に採番した場合LOCKを掛けて(排他制御)採番します。
// 主に受付番号や注文番号など主キーとして採番するのに利用します。
// COMMITされるまでLOCK状態になります。
//
// 採番用のテーブルを準備します。
// スキーマ :PTW
// テーブル名:AUTO_NO
// 項目名 :SQNO
//----------------------------
//■自動採#作業
//----------------------------
string w_sql_errtext, w_kubun
Dec Con
//
SELECT "PTW"."AUTO_NO"."SQNO"
INTO :Con
FROM "PTW"."AUTO_NO" for UPDATE using SQLCA ;
//
if SQLCA.SQLCODE <> 0 then
//データベースエラー
w_sql_errtext = SQLCA.SQLErrText
rollback using SQLCA; //排他制御を解除するためにROLLBACKを行なう
MessageBox("自動採番 排他制御エラー", "排他制御エラー(読込):" + w_sql_errtext , StopSign!)
//エラー終了(返却値マイナス1を返して終了)
return
end if
//Messagebox("自動採#","自動採#:" + String(Con))
//----------------------------------------------
// 管理コードのカウントを進める
//----------------------------------------------
if Con = 9999 then
Con = 0
else
Con = Con + 1
end if
//管理コードのカウント+1加算し登録する。(排他制御)
UPDATE "PTW"."AUTO_NO"
SET "SQNO" = :Con using SQLCA ;
//
if SQLCA.SQLNROWS < 1 then
//データベースエラー
w_sql_errtext = SQLCA.SQLErrText
rollback using SQLCA;
MessageBox("自動採番 排他制御エラー", "排他制御エラー(書込):" + w_sql_errtext , StopSign!)
//エラー終了(返却値マイナス1を返して終了)
return
end if
// 採番セット
em_pno.text = string(Con)
commit using SQLCA;