結局のところ、誰もが知っていますが、誰もが理解しているわけではありません。 mysqlおよびSELECT FOR UPDATEのトランザクション

私の義務のために、「[シニア|ジュニア] python / django開発者」、「チームリード」という立場でインタビューを行うことがあります。 驚いたことに、「Mysql / Innodb / transactions / triggers / stored procなど」という言葉の概要を示した10人中9人の求職者が、彼らとの過去の経験についてまったく何も言えないことがわかりました。 残念ながら、ユースケースの説明は1つも受け取っていません。



さらにインタビューでは、次の状況に対する解決策を提案することを提案しました。



私たちがオンラインサービスであり、ある種の外部有料API(サービスのアクティベーション、有料コンテンツ、またはあなたの心が望むもの)を順番に使用すると仮定します。つまり、私たちのサービスはAPIの使用に対してお金を支払います。 システム内のユーザーがサービスをアクティブ化するリクエストを作成し、すべてのフィールドに入力し、最後のページで「サービスをアクティブ化」ボタンを押します。 つまり、HTTPリクエストを送信した時点で、データベース(サービスをアクティブにするリクエスト)にレコードがあります。 私たちのアルゴリズムは何ですか?-私は尋ねて、続けます:



-データベースからユーザーの残高を取得します。

-十分なバランスがある場合は、APIをプルします。

-すべてが正常である場合は、貸借対照表からサービスの金額を差し引き、更新、コミット、またはロールバックします。

-ユーザーに応答します。



すべては些細なことのように思えますが、最初の最も明白な問題を10の競合リクエスト(最初はすべて同じバランスを取り、APIの呼び出しを開始)の形でもたらすと、5つの選択肢から始まる最も洗練されたソリューションが提供され始めます(私は認めなければなりません、私はこのオプションでは何も理解していませんでした)、自動インクリメントカウンター、外部キャッシュ、データベース内の新しいテーブル、スリップの使用、そして何を理解していないか。



ご存知のように(そしてすべての候補者はこれを知っていました!)、mysqlのInnodbはトランザクションメカニズムと行ごとにブロックする機能を提供します。 この同じ行ロックを適用するには、次のように、SELECTの最後にFOR UPDATE式を追加するだけです。



SELECT * FROMリクエストWHERE ID = 5 FOR UPDATE



トランザクションが開始され、データベースに対する他のすべてのセッションは、トランザクションが完了するまで同様のリクエストを処理できず、単に待機します。 読み取りの場合、レコードはトランザクションの分離レベルに依存する状態で利用可能になります。



また、FOR UPDATEの使用は、自動コミットをオフにして行うのが最適であることに注意してください。何をロックしても、最初の更新後にロックが解除されるためです。



些細なことのように思えますが、明らかなようですが、10分の9 ...



更新した

記事には開示されていない以前の名前「Transactions in mysql」は、「Transactions in mysql and SELECT FOR UPDATE」に置き換えられました



脅威

この記事では、トランザクションの一部としてAPIをプルする必要があること、および障害が発生した場合の処理​​と例外的な状況の処理方法については言及していません。



All Articles