部屋とタグの間の一貫性を実現し、部屋が削除された後に部屋が返されないようにする唯一のポータブルな方法は、SELECT FOR UPDATE
で部屋をロックすることです。 。
ただし、一部のシステムでは、ロックは同時実行制御の副作用であり、FOR UPDATE
を指定しなくても同じ結果が得られます。 明示的に。
この問題を解決するには、スレッド1で
SELECT id FROM rooms FOR UPDATE
を実行する必要があります。 、これにより、スレッド2がrooms
から削除されるのを防ぎます。 スレッド1が完了するまで。それは正しいですか?
これは、データベースシステムが使用している同時実行制御によって異なります。
-
MyISAM
MySQL
で (および他のいくつかの古いシステム)は、クエリの間、テーブル全体をロックします。 -
SQL Server
内 、SELECT
クエリは、調査したレコード/ページ/テーブルに共有ロックを設定しますが、DML
クエリは更新ロックを配置します(後で排他的ロックに昇格されるか、共有ロックに降格されます)。排他的ロックは共有ロックと互換性がないため、SELECT
またはDELETE
別のセッションがコミットするまでクエリはロックされます。 -
MVCC
を使用するデータベース (Oracle
のように 、PostgreSQL
、MySQL
InnoDB
を使用 )、DML
クエリは(何らかの方法で)レコードのコピーを作成し、通常、リーダーはライターをブロックしません。その逆も同様です。これらのデータベースの場合、SELECT FOR UPDATE
便利です:SELECT
のいずれかをロックします またはDELETE
SQL Server
と同様に、別のセッションがコミットされるまでクエリを実行します
いつ
REPEATABLE_READ
を使用する必要がありますか トランザクション分離とREAD_COMMITTED
SELECT ... FOR UPDATE
を使用 ?
通常、REPEATABLE READ
ファントム行(変更されるのではなく、別のトランザクションで表示または非表示になった行)を禁止しません
-
Oracle
内 以前のPostgreSQL
バージョン、REPEATABLE READ
実際にはSERIALIZABLE
の同義語です 。基本的に、これは、トランザクションが開始後に行われた変更をトランザクションが認識しないことを意味します。したがって、このセットアップでは、最後のThread 1
クエリは、部屋が削除されたことがないかのように部屋を返します(これはあなたが望むものである場合とそうでない場合があります)。削除された後に部屋を表示したくない場合は、SELECT FOR UPDATE
で行をロックする必要があります -
InnoDB
内 、REPEATABLE READ
およびSERIALIZABLE
異なるものです:SERIALIZABLE
のリーダー モードは、評価するレコードの次のキーのロックを設定し、同時のDML
を効果的に防止します それらの上に。したがって、SELECT FOR UPDATE
は必要ありません。 シリアル化可能モードですが、REPEATABLE READ
で必要です。 またはREAD COMMITED
。
分離モードの標準では、クエリに特定の癖が見られないことを規定していますが、その方法(ロックまたはMVCC
を使用)は定義されていないことに注意してください。 またはそれ以外の場合)。
「SELECT FOR UPDATE
は必要ありません 「「特定のデータベースエンジン実装の副作用のために」追加する必要がありました。