部屋とタグの間の一貫性を実現し、部屋が削除された後に部屋が返されないようにする唯一のポータブルな方法は、SELECT FOR UPDATEで部屋をロックすることです。 。
ただし、一部のシステムでは、ロックは同時実行制御の副作用であり、FOR UPDATEを指定しなくても同じ結果が得られます。 明示的に。
この問題を解決するには、スレッド1で
SELECT id FROM rooms FOR UPDATEを実行する必要があります。 、これにより、スレッド2がroomsから削除されるのを防ぎます。 スレッド1が完了するまで。それは正しいですか?
これは、データベースシステムが使用している同時実行制御によって異なります。
-
MyISAMMySQLで (および他のいくつかの古いシステム)は、クエリの間、テーブル全体をロックします。 -
SQL Server内 、SELECTクエリは、調査したレコード/ページ/テーブルに共有ロックを設定しますが、DMLクエリは更新ロックを配置します(後で排他的ロックに昇格されるか、共有ロックに降格されます)。排他的ロックは共有ロックと互換性がないため、SELECTまたはDELETE別のセッションがコミットするまでクエリはロックされます。 -
MVCCを使用するデータベース (Oracleのように 、PostgreSQL、MySQLInnoDBを使用 )、DMLクエリは(何らかの方法で)レコードのコピーを作成し、通常、リーダーはライターをブロックしません。その逆も同様です。これらのデータベースの場合、SELECT FOR UPDATE便利です:SELECTのいずれかをロックします またはDELETESQL Serverと同様に、別のセッションがコミットされるまでクエリを実行します
いつ
REPEATABLE_READを使用する必要がありますか トランザクション分離とREAD_COMMITTEDSELECT ... 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は必要ありません 「「特定のデータベースエンジン実装の副作用のために」追加する必要がありました。