排他制御(テーブルロック)の方法

内容

テーブル項目を使っている時に、テーブルをロックして他のユーザが利用出来なく

(しばらく待ち状態)にして、処理が終わったら解放する。

 良く使うのが、「採番」処理の時です。受付番号や受注番号、注文番号等

絶対に重複した番号を取らない様にする場合などに排他制御を使った処理を行います。

#排他制御 #ロック #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;