web-dev-qa-db-ja.com

ACIDトランザクションinnodb内の行ロック

私は次のような金融取引をしています(疑似):

begin
    select record for update
    update record(same record as selected)
    insert another record into another table
commit

SELECT ... FOR UPDATEトランザクション内で、トランザクションがコミットされた場合にのみ、特定の行のロックが解放されますか?

2
tommo

MySQL 5.0認定試験ガイドの418パラグラフ3によると

MySQL 5.0 Certification Study Guide

次のコマンドはトランザクションを破壊する可能性があります

  • ALTER TABLE
  • BEGIN
  • CREATE INDEX
  • DROP DATABASE
  • DROP INDEX
  • DROP TABLE
  • RENAME TABLE
  • TRUNCATE TABLE
  • LOCK TABLES
  • UNLOCK TABLES
  • SET AUTOCOMMIT = 1
  • START TRANSACTION

トランザクション内でこれらのコマンドを実行しない限り、トランザクションは安定しているはずです。実際、SELECT FOR UPDATEは非常に強力なので、行ロックはデータだけでなくインデックスにも侵入します。それは可能なInnoDBデッドロックを相殺することさえできました。私はかつてこの投稿でそれについて書いた: select for updateはインデックスされたカラムにエラーを与える

トランザクションを短く簡潔に保つ限り、SELECT FOR UPDATEは問題ありません。トランザクションを断続的または予期しないデッドロックから保護する場合、MySQL 5.6には次のものが含まれます。

  • START TRANSACTION READ WRITE;
  • START TRANSACTION READ ONLY;

これらのようなオプションでトランザクションを開始する必要があります。どうして ?

そのMySQLドキュメント によると:

READ WRITEおよびREAD ONLY修飾子は、トランザクションアクセスモードを設定します。トランザクションで使用されるテーブルへの変更を許可または禁止します。 READ ONLY制限は、他のトランザクションから見えるトランザクションテーブルと非トランザクションテーブルの両方をトランザクションが変更またはロックすることを防ぎます。トランザクションは引き続き一時テーブルを変更またはロックできます。これらの修飾子は、MySQL 5.6.5以降で使用できます。

あなたの最後のコメントは

トランザクション内の行を更新用とは別の方法でロックできますか

SELECT ... LOCK IN SHARE MODE を実行することもできます。ドキュメントは言う

  • SELECT ... LOCK IN SHARE MODEは、読み取られたすべての行に共有モードロックを設定します。他のセッションは行を読み取ることができますが、トランザクションがコミットするまでそれらを変更することはできません。これらの行のいずれかがまだコミットされていない別のトランザクションによって変更された場合、クエリはそのトランザクションが終了するまで待機してから、最新の値を使用します。
  • 検索で検出されるインデックスレコードの場合、SELECT ... FOR UPDATEは、行と関連するインデックスエントリをロックします。これらの行に対してUPDATEステートメントを発行した場合と同じです。他のトランザクションは、これらの行の更新、SELECT ... LOCK IN SHARE MODEの実行、または特定のトランザクション分離レベルでのデータの読み取りからブロックされます。一貫した読み取りでは、読み取りビューに存在するレコードに設定されたロックは無視されます。 (レコードの古いバージョンはロックできません。レコードのメモリ内コピーに元に戻すログを適用することで再構築されます。)

可能ですが、トランザクションは短くしてください。そうしないと、デッドロックの可能性が高まります。

UPDATE 2014-02-13 21:57 EST

誤解を解消するために、 MySQLのドキュメントからこれに注意してください

LOCK IN SHARE MODE および FOR UPDATE クエリによって設定されたすべてのロックは、トランザクションがコミットまたはロールされるときに解放されますバック。

したがって、トランザクション内で SELECT ... LOCK IN SHARE MODE を実行すると、トランザクションがコミットまたはロールバックするまで、行はロックされたままになります。

4
RolandoMySQLDBA

また、例外ハンドラーがループ外にあり、トランザクションスコープがループ内にある場合でもLOOPは、mysqlが例外時にトランザクションを中断します。同じスコープのトランザクションが宣言されている場合は、例外ハンドラーを宣言する方が適切です。

1
satya