OceanBaseデータベースはマルチバージョン同時実行制御(MVCC)をサポートしています。デフォルトでは、読み取りトランザクションは書き込みトランザクションの実行をブロックしませんが、SELECT ... FOR UPDATE の方法を使用して読み取りトランザクションの対象にロックをかけることで、書き込みトランザクションをブロックすることができます。
本記事では具体的な例を通じて、SELECT FOR UPDATE を使用してクエリ結果をロックする方法を紹介します。
例
SELECT FOR UPDATE を使用してクエリ結果をロックします。
サンプルテーブルを作成し、適切なデータを挿入します。
以下のSQLステートメントを実行して、
test_tbl1テーブルを作成します。CREATE TABLE test_tbl1(id number, name VARCHAR(18), c_date date, PRIMARY KEY (id) );以下のSQLステートメントを実行して、
test_tbl1テーブルにデータを挿入します。INSERT INTO test_tbl1 VALUES(1,'A1',date'2019-09-09'), (2,'B1',date'2019-06-06'), (3,'C1',date'2019-05-05'), (4,'D1',date'2020-02-02'), (5,'F1',date'2021-01-01');以下のSQLステートメントを実行して、トランザクションをコミットします。
COMMIT;
セッション1 では、
FOR UPDATE構文を使用して、テーブルtest_tbl1中のid値が1となるレコードに対してクエリを実行し、行ロックを追加します。全ての並列する更新がブロックされ、待機します。SELECT name,c_date FROM test_tbl1 WHERE id = 1 FOR UPDATE;実行結果は次のとおりです:
+------+-----------+ | NAME | C_DATE | +------+-----------+ | A1 | 09-SEP-19 | +------+-----------+ 1 row in setセッション2 で、次のSQLステートメントを実行して、テーブル
test_tbl1のid値が1に等しい行の対応するnameのをA1A1に変更します。このSQLステートメントは、セッション1 のトランザクションがROLLBACKまたはCOMMITされるまで待機し、その後に実行されます。UPDATE test_tbl1 SET name = 'A1A1' WHERE id = 1;実行結果は次のとおりです:
OBE-30006: resource busy; acquire with WAIT timeout expiredセッション1 で、以下のSQLステートメントを実行してトランザクションをコミットします。
COMMIT;セッション2 で、再び ステップ3 の更新ステートメントを実行します。
UPDATE test_tbl1 SET name = 'A1A1' WHERE id = 1;実行結果は次のとおりです:
Query OK, 1 row affected Rows matched: 1 Changed: 1 Warnings: 0セッション2 で、以下のSQLステートメントを実行してトランザクションをコミットします。
COMMIT;セッション1 で更新されたデータをクエリします。
SELECT name,c_date FROM test_tbl1 WHERE id = 1;実行結果は次のとおりです:
+------+-----------+ | NAME | C_DATE | +------+-----------+ | A1A1 | 09-SEP-19 | +------+-----------+ 1 row in set