OceanBase Cloudはマルチバージョン同時実行制御(MVCC)をサポートしています。デフォルトでは、読み取りトランザクションは書き込みトランザクションをブロックしません。SELECT ... FOR UPDATE ステートメントを使用して、読み取りトランザクションが対象とするオブジェクトをロックし、書き込みトランザクションをブロックできます。
本記事では、具体的な例を通じて SELECT ... FOR UPDATE ステートメントを使用してクエリ結果をロックする方法を説明します。
例
SELECT ... FOR UPDATE ステートメントを使用してクエリ結果をロックします。
テーブルを作成し、データを挿入します。
test_tbl1という名前のテーブルを作成します。CREATE TABLE test_tbl1(id number, name VARCHAR(18), c_date date, PRIMARY KEY (id) );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');トランザクションをコミットします。
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;実行結果は次のとおりです:
ORA-30006: resource busy; acquire with WAIT timeout expiredセッション1 で、以下のSQLステートメントを実行してトランザクションをコミットします:
COMMIT;セッション2 で、再度 手順3 の
UPDATEステートメントを実行します。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