SQLとロック戦略について質問があります。例として、自分のWebサイトに画像のビューカウンターがあるとします。次のステートメントを実行するためのsprocなどがある場合:
START TRANSACTION;
UPDATE images SET counter=counter+1 WHERE image_id=some_parameter;
COMMIT;
特定のimage_idのカウンターの値が時間t0で「0」であると想定します。同じイメージカウンターs1とs2を更新する2つのセッションがt0で同時に開始する場合、これら2つのセッションが両方とも値「0」を読み取り、値を「1」に増やし、両方がカウンターを「1」に更新しようとする可能性があります。 '、したがって、カウンターは'2'ではなく'1'の値を取得しますか?
s1: begin
s1: begin
s1: read counter for image_id=15, get 0, store in temp1
s2: read counter for image_id=15, get 0, store in temp2
s1: write counter for image_id=15 to (temp1+1), which is 1
s2: write counter for image_id=15 to (temp2+1), which is also 1
s1: commit, ok
s2: commit, ok
最終結果:image_id=15の誤った値「1」は2である必要があります。
私の質問は次のとおりです。
- このシナリオは可能ですか?
- もしそうなら、トランザクション分離レベルは重要ですか?
- エラーなどの競合を検出する競合解決機能はありますか?
- 問題を回避するために特別な構文を使用できますか(コンペアアンドスワップ(CAS)や明示的なロック手法など)?
私は一般的な答えに興味がありますが、MySqlとInnoDB固有の答えがない場合は、この手法を使用してInnoDBにシーケンスを実装しようとしているため、興味があります。
編集:次のシナリオも可能であり、同じ動作になります。分離レベルがREAD_COMMITED以上であると想定しているため、s1はすでにカウンターに「1」を書き込んでいますが、s2はトランザクションの開始から値を取得します。
s1: begin
s1: begin
s1: read counter for image_id=15, get 0, store in temp1
s1: write counter for image_id=15 to (temp1+1), which is 1
s2: read counter for image_id=15, get 0 (since another tx), store in temp2
s2: write counter for image_id=15 to (temp2+1), which is also 1
s1: commit, ok
s2: commit, ok