プログラミングお勉強 @Wiki

Firebirdにおける行ロックを考える

最終更新:

匿名ユーザー

- view
メンバー限定 登録/ログイン
#blognavi
とりあえず、Firebirdは動くようになり、管理ツールも使えるようになった。というところで、気になったのは、行ロックの制御がどれくらいできるのかということだった。

DBで行ロックの制御がちゃんとできないとプログラム側での労力が大きい。
SQL Server でも ORACLEでも変わらないと思っている人も結構いるようだが、やはりDBの機能差は上位アプリを開発する上ではかなり影響する。ORACLEの機能を有効に使うことでだいぶコードは減るものだ。
という点の一つ大きいところがこのロック制御に他ならない。

Firebirdへの接続

DBに接続。
 SQL> connect "/opt/firebird/examples/employee.fdb"
 CON> user 'sysdba' password 'welcome';
 Database:  "/opt/firebird/examples/employee.fdb", User: sysdba
CUSTOMER表の構成を見る。
 SQL> show table customer;
 CUST_NO                         (CUSTNO) INTEGER Not Null
                                 CHECK (VALUE > 1000)
 CUSTOMER                        VARCHAR(25) Not Null
 CONTACT_FIRST                   (FIRSTNAME) VARCHAR(15) Nullable
 CONTACT_LAST                    (LASTNAME) VARCHAR(20) Nullable
 PHONE_NO                        (PHONENUMBER) VARCHAR(20) Nullable
 ADDRESS_LINE1                   (ADDRESSLINE) VARCHAR(30) Nullable
 ADDRESS_LINE2                   (ADDRESSLINE) VARCHAR(30) Nullable
 CITY                            VARCHAR(25) Nullable
 STATE_PROVINCE                  VARCHAR(15) Nullable
 COUNTRY                         (COUNTRYNAME) VARCHAR(15) Nullable
 POSTAL_CODE                     VARCHAR(12) Nullable
 ON_HOLD                         CHAR(1) Nullable DEFAULT NULL
 CONSTRAINT INTEG_61:
 Foreign key (COUNTRY)    References COUNTRY (COUNTRY)
 CONSTRAINT INTEG_60:
   Primary key (CUST_NO)
 CONSTRAINT INTEG_59:
   CHECK (on_hold IS NULL OR on_hold = '*')
 
 Triggers on Table CUSTOMER:
 SET_CUST_NO, Sequence: 0, Type: BEFORE INSERT, Active
CUSTOMER表を検索してみる。
 SQL> select cust_no,customer from customer where cust_no=1001;
 
      CUST_NO CUSTOMER
 ============ =========================
 
         1001 Signature Design
 
 SQL>

ロックを発生させる。

TELNETでA,B2箇所からfirebirdに接続する。

Aで実行。
 SQL> select cust_no,customer from customer where cust_no=1001 for update;
 
      CUST_NO CUSTOMER
 ============ =========================
 
         1001 Signature Design
 
 SQL>

Bで実行。ここでロックを発生させる。
 SQL> select cust_no,customer from customer where cust_no=1001 for update;
 
      CUST_NO CUSTOMER
 ============ =========================
 
         1001 Signature Design
 
 SQL>

と、どちらもSELECTできてしまい、ロックがかからなかった。

次にUPDATE句で実行する。
Aで実行。
 SQL> update customer set contact_last='TEST' where cust_no=1001;
 SQL>
Bで実行。
 SQL> update customer set contact_last='TEST' where cust_no=1001;

これでBではロックがかかっている為、WAITになる。

次に、SELECT FOR UPDATE句でのロックを再度確認。
「with lock」をつけることでロックをつけられた。

 SQL> select cust_no,customer from customer where cust_no=1001 for update with lock;
 
      CUST_NO CUSTOMER
 ============ ========================= 
 
         1001 Signature Design
 
 SQL>
これをBでも実行するとロックのためのWAITになる。
またBで1002を検索すると、ロックを取得できる。
 SQL> select cust_no,customer from customer where cust_no=1002 for update with lock;
 
      CUST_NO CUSTOMER
 ============ =========================
 
         1002 Dallas Technologies
 
 SQL>
これでUPDATE及びSELECT FOR UPDATEで行ロックがちゃんとかかる。

NO WAITのテスト。

次に、NO WAITのテスト。プログラムの中ではロック解除を待たずにエラーで返してくれる方が良い場合もある。ということで、ロックしているデータの場合は即エラーで返す設定を確認する。

Aで上記と同様でロックをかける。
Bで下記を実行。
 SQL> set transaction no wait;
これでロック時にはWAITをかけずにエラーする。
 SQL> select cust_no,customer from customer where cust_no=1001 for update with lock;
 
      CUST_NO CUSTOMER
 ============ =========================
 Statement failed, SQLCODE = -901
 
 lock conflict on no wait transaction
 -deadlock
 -update conflicts with concurrent update
 SQL>

デッドロックチェック

次にはデッドロックの場合どのようなエラーを返すか確認する。

Aで下記を実行。
 SQL> set transaction wait;
 SQL> select cust_no,customer from customer where cust_no=1001 for update with lock;
 
      CUST_NO CUSTOMER
 ============ =========================
 
         1001 Signature Design
このとき、Bで下記を実行する。
 SQL> set transaction wait;
 SQL> select cust_no,customer from customer where cust_no=1002 for update with lock;
 
      CUST_NO CUSTOMER
 ============ =========================
 
         1002 Dallas Technologies

これでAがCUST_NO=1001、BがCUST_NO=1002をそれぞれロックしている。
このときに、Bで下記を実行。

 SQL> select cust_no,customer from customer where cust_no=1001 for update with lock;

これでBはロック待ち状態に入る。

Aでデッドロックを発生させる。
 SQL> select cust_no,customer from customer where cust_no=1002 for update with lock;

これでデッドロック完成。すると1,2秒後に下記のエラーが発生。
      CUST_NO CUSTOMER
 ============ =========================
 Statement failed, SQLCODE = -913
 
 deadlock
 -deadlock
 -update conflicts with concurrent update

上記でロック系の確認を一通りした。
フリーのDBということでロックについてはあまり期待していなかったが結構実用に耐えうるものと思えた。




カテゴリ: [Firebird] - &trackback() - 2005年09月05日 00:25:25
名前: コメント:
#blognavi
記事メニュー
目安箱バナー