PostgreSQL-ロック
ロックまたは排他ロックまたは書き込みロックは、ユーザーが行またはテーブル全体を変更できないようにします。UPDATEおよびDELETEによって変更された行は、トランザクションの期間中、自動的に排他的にロックされます。これにより、トランザクションがコミットまたはロールバックされるまで、他のユーザーが行を変更できなくなります。
ユーザーが他のユーザーを待たなければならないのは、同じ行を変更しようとしているときだけです。異なる行を変更する場合、待機する必要はありません。SELECTクエリは待つ必要はありません。
データベースは自動的にロックを実行します。ただし、場合によっては、ロックを手動で制御する必要があります。手動ロックは、LOCKコマンドを使用して実行できます。これにより、トランザクションのロックタイプとスコープを指定できます。
LOCKコマンドの構文
LOCKコマンドの基本的な構文は次のとおりです。
LOCK [ TABLE ]
name
IN
lock_mode
name−ロックする既存のテーブルの名前(オプションでスキーマ修飾)。テーブル名の前にONLYが指定されている場合、そのテーブルのみがロックされます。ONLYが指定されていない場合、テーブルとそのすべての子孫テーブル(存在する場合)がロックされます。
lock_mode−ロックモードは、このロックが競合するロックを指定します。ロックモードが指定されていない場合は、最も制限の厳しいモードであるACCESSEXCLUSIVEが使用されます。可能な値は、ACCESS SHARE、ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE、ACCESSEXCLUSIVEです。
取得されると、ロックは現在のトランザクションの残りの間保持されます。UNLOCKTABLEコマンドはありません。ロックは常にトランザクションの終了時に解放されます。
DeadLocks
デッドロックは、2つのトランザクションが相互に操作を終了するのを待っているときに発生する可能性があります。PostgreSQLはそれらを検出し、ROLLBACKで終了できますが、デッドロックは依然として不便な場合があります。アプリケーションでこの問題が発生しないようにするには、オブジェクトを同じ順序でロックするようにアプリケーションを設計してください。
アドバイザリーロック
PostgreSQLは、アプリケーション定義の意味を持つロックを作成するための手段を提供します。これらはアドバイザリロックと呼ばれます。システムはそれらの使用を強制しないので、それらを正しく使用するのはアプリケーション次第です。アドバイザリロックは、MVCCモデルに不自然に適合するロック戦略に役立ちます。
たとえば、アドバイザリロックの一般的な使用法は、いわゆる「フラットファイル」データ管理システムに典型的な悲観的なロック戦略をエミュレートすることです。テーブルに格納されているフラグは同じ目的で使用できますが、アドバイザリロックはより高速で、テーブルの肥大化を回避し、セッションの終了時にサーバーによって自動的にクリーンアップされます。
例
次のようなレコードを持つテーブルCOMPANYについて考えてみます。
testdb# select * from COMPANY;
id | name | age | address | salary
----+-------+-----+-----------+--------
1 | Paul | 32 | California| 20000
2 | Allen | 25 | Texas | 15000
3 | Teddy | 23 | Norway | 20000
4 | Mark | 25 | Rich-Mond | 65000
5 | David | 27 | Texas | 85000
6 | Kim | 22 | South-Hall| 45000
7 | James | 24 | Houston | 10000
(7 rows)
次の例では、testdbデータベース内のCOMPANYテーブルをACCESSEXCLUSIVEモードでロックします。LOCKステートメントはトランザクションモードでのみ機能します-
testdb=#BEGIN;
LOCK TABLE company1 IN ACCESS EXCLUSIVE MODE;
上記のPostgreSQLステートメントは次の結果を生成します-
LOCK TABLE
上記のメッセージは、トランザクションが終了するまでテーブルがロックされていることを示しています。トランザクションを終了するには、トランザクションをロールバックまたはコミットする必要があります。