PostgreSQLのトランザクションとロックに関する解説
トランザクションとは
トランザクションは、データベースにおける一連の操作をひとまとめにして扱う仕組みです。これにより、複数の操作が一度に成功するか、失敗しても前の状態に戻すことができます。トランザクションは、ACID特性を持ちます。ACIDは、以下の4つの特性の頭文字を取ったものです。
- Atomicity (原子性): すべての操作が成功するか、全て失敗して元の状態に戻ること。
- Consistency (一貫性): トランザクションが終了したとき、データベースが一貫した状態に保たれること。
- Isolation (独立性): 他のトランザクションの影響を受けないこと。
- Durability (耐久性): トランザクションが完了した後、その結果が永続的に保存されること。
トランザクションを利用することで、複数の処理を安全に、効率的に行うことが可能です。
BIGIN, COMMIT, ROLLBACKについて
トランザクションを制御するために、以下の3つのコマンドを使用します。
BEGIN
トランザクションの開始を宣言するために使用します。トランザクション内の最初のSQL文の前に書きます。例えば、以下のように記述します。
BEGIN;
これにより、その後のSQL操作はすべてトランザクション内で実行され、必要に応じてコミットまたはロールバックできます。
COMMIT
トランザクションが正常に完了したことをデータベースに通知し、実行した変更を確定します。例えば、以下のように記述します。
COMMIT;
これにより、トランザクション内で行われたすべての変更がデータベースに反映され、永続化されます。
ROLLBACK
トランザクションが失敗した場合や、途中で取り消したい場合に、トランザクションをキャンセルするために使用します。例えば、以下のように記述します。
ROLLBACK;
これにより、トランザクション内で行ったすべての変更が取り消され、データベースはトランザクション開始前の状態に戻ります。
行レベルロック(FOR UPDATE/SHARE)
行レベルロックは、特定の行に対してロックをかける方法です。複数のトランザクションが同じテーブルの異なる行を操作している場合、データの競合を避けるために利用されます。行レベルロックを使用するには、FOR UPDATE
またはFOR SHARE
を使用します。
FOR UPDATE
FOR UPDATE
は、選択した行を他のトランザクションが変更できないようにロックします。このロックは、トランザクションが終了するまで解除されません。例えば、次のように使用します。
SELECT * FROM users WHERE id = 1 FOR UPDATE;
このクエリは、idが1のユーザーを選択し、その行をロックして他のトランザクションが変更できないようにします。
FOR SHARE
FOR SHARE
は、選択した行を他のトランザクションが変更できないようにロックしますが、読み取りは許可されます。このロックは、複数のトランザクションが同時に読み取ることを許可しつつ、書き込みを防ぎます。例えば、次のように使用します。
SELECT * FROM products WHERE price > 100 FOR SHARE;
これにより、価格が100より大きいすべての製品がロックされ、他のトランザクションがその行を変更することはできませんが、読み取ることはできます。
テーブルロック(LOCK)
テーブルロックは、テーブル全体にロックをかける方法です。これにより、他のトランザクションがそのテーブルを変更できなくなります。テーブルロックは、LOCK
コマンドを使って行います。例えば、次のように記述します。
LOCK TABLE employees IN EXCLUSIVE MODE;
このコマンドは、employeesテーブルを独占的にロックし、他のトランザクションがそのテーブルにアクセスすることを防ぎます。ロックの種類には、いくつかのモードがあります。
LOCKモード
PostgreSQLでは、以下のようなロックモードが使用できます:
- ACCESS SHARE MODE: 最も低いレベルのロックで、SELECT操作は許可されます。
- ROW SHARE MODE: 行レベルのロックを取得し、行を選択して更新することを許可します。
- EXCLUSIVE MODE: テーブルに対する排他的なロックで、他のトランザクションがそのテーブルにアクセスするのを完全に防ぎます。
ロックモードを適切に選択することで、データベースの性能と整合性を保つことができます。