読み取り一貫性は、状況によっては不便な場合があります。
テーブル CHILD
に新しいレコードを追加するために、テーブル
PARENT
内にこの子レコードの親がすでに存在することを確認するとします。
仮に、読み取り一貫性でテーブル
PARENT
を読み取り、このテーブルで子レコードの親の存在を確認したとします。これでテーブル
CHILD
に子レコードを確実に追加できるでしょうか。できません。この処理の間に他のユーザがテーブル
PARENT
から親レコードを削除しても気付かないからです。
これに対処するには、共有ロックモード
LOCK IN SHARE MODE
で
SELECT
文を実行します。
SELECT * FROM PARENT WHERE NAME = 'Jones' LOCK IN SHARE MODE;
共有モードで読み取りを実行すると、入手可能な最新のデータが読み取られ、読み取ったレコードに共有モードロックが設定されます。
その最新データが、別のユーザのまだコミットされていないトランザクションに属している場合は、そのトランザクションがコミットされるまで待機します。
共有モードロックによって、読み取ったレコードは他のユーザから更新または削除されなくなります。上記のクエリから親である
'Jones'
が返されたことを確認したうえで、テーブル
CHILD
に 'Jones'
の子レコードを確実に追加し、トランザクションをコミットできます。
この例は、アプリケーションコードで参照整合性を実装する方法を示しています。
別の例を見てみましょう。テーブル
CHILD_CODES
に整数のカウンタフィールドがあります。このテーブルは、テーブル
CHILD
に追加する各子に一意の識別子を割り当てるために使用します。
このカウンタの現在の値を読み取る場合に、読み取り一貫性または共有モード読み取りが適していないのは明らかです。これは、データベースの
2
人のユーザに同じカウンタ値が返されるために、テーブルに同じ識別子を持つ
2
つの子を追加することになり、重複キーエラーが発生するためです。
この場合、カウンタの読み取りとインクリメントを実装する方法が
2 つあります。(1)カウンタを先に 1
増加してから読み取る方法と(2)カウンタを先にロックモード
FOR UPDATE
で読み取ってからインクリメントする方法です。
SELECT COUNTER_FIELD FROM CHILD_CODES FOR UPDATE; UPDATE CHILD_CODES SET COUNTER_FIELD = COUNTER_FIELD + 1;
SELECT ... FOR UPDATE
では、入手可能な最新のデータが読み取られ、読み取った各レコードに排他ロックが設定されます。
したがって、検索された SQL
UPDATE
がレコードに設定するロックと同じロックが設定されます。
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.