sql >> データベース >  >> RDS >> Mysql

MySQLトランザクションでのレイテンシの処理

    すべてを1つの大きなクエリにカプセル化する必要がないのは、実際には何も解決されないためです。

    必要なのは、行のロック、または新しい行が挿入されるインデックスのロックです。

    では、どうすれば排他ロックを取得できますか?

    2つの接続、mysql1とmysql2。それぞれがSELECT ... FOR UPDATEを使用して排他ロックを要求します。 。テーブル'history'には、インデックスが付けられた列'user_id'があります。 (これは外部キーでもあります。)行が見つからないため、どちらも異常が発生しないかのように正常に進行しているように見えます。 user_id 2808は有効ですが、履歴には何もありません。

    mysql1> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql2> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql1> select * from history where user_id = 2808 for update;
    Empty set (0.00 sec)
    
    mysql2> select * from history where user_id = 2808 for update;
    Empty set (0.00 sec)
    
    mysql1> insert into history(user_id) values (2808);
    

    ...プロンプトが返されません...応答がありません...別のセッションにもロックがあるため...しかし:

    mysql2> insert into history(user_id) values (2808);
    ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
    

    次に、mysql1は挿入時にすぐに成功を返します。

    Query OK, 1 row affected (3.96 sec)
    

    残っているのは、mysql1がCOMMITすることだけです。 そして魔法のように、0エントリのユーザーが複数のエントリを挿入するのを防ぎました。デッドロックが発生したのは、両方のセッションで互換性のないことが発生する必要があるためです。mysql1は、コミットする前にmysql2がロックを解放する必要があり、mysql2は、挿入できるようになる前にmysql1がロックを解放する必要がありました。誰かがその戦いに負ける必要があり、一般的に最も少ない仕事をしたスレッドが敗者です。

    しかし、SELECT ... FOR UPDATEを実行したときに、すでに1つ以上の行が存在していた場合はどうなりますか。 ?その場合、ロックは行にあるため、SELECTを試行する2番目のセッション SELECTの待機を実際にブロックします 最初のセッションがCOMMITのいずれかを決定するまで またはROLLBACK 、その時点で、2番目のセッションは行数の正確なカウント(最初のセッションによって挿入または削除されたものを含む)を確認し、ユーザーがすでに最大許容数を持っていると正確に判断できたはずです。

    競合状態を超えることはできませんが、それらをロックアウトすることはできます。




    1. mysqlでalterを使用して列を追加する方法は?

    2. Perl DBIクエリが返す行数を知るにはどうすればよいですか?

    3. PostgreSQL9.1での自律型トランザクション

    4. SQLの2つの既存の行の間にテーブルに行を挿入する方法