秒殺システムの超買問題の詳細


目次
  • 1.シーン
  • 2. 方法
  • 3.まとめ
  • 1.シーン
    現在在庫が1つの商品しかないと仮定すると、マルチスレッドの下で最終在庫がマイナスではなく0であることを保証する方法
    2.方法
  • MySQLの排他ロック
  • update goods set num = num - 1 WHERE id = 1001 and num > 0
    

    排他ロックは書き込みロックとも呼ばれ、Xロックと略称され、その名の通り、排他ロックは他のトランザクションと共存できない.例えば、1つのトランザクションがデータ行の排他ロックを取得した場合、他のトランザクションは共有ロックと排他ロックを含む他のロックを取得できないが、排他ロックを取得したトランザクションはデータ行の読み取りと修正を行うことができる.私がupdate操作を実行しているときと同じように、この行はトランザクションです(デフォルトでは排他ロックが追加されています).この行は他のスレッドによって変更および読み書きできません.
  • バージョン番号方式
  • を採用
    select version from goods WHERE id= 1001;
    update goods set num = num - 1, version = version + 1 WHERE id= 1001 AND version = @version(     version);
    
  • この方式はバージョン番号方式を採用しているが、実はCASの原理である.
  • は、このときversion=100、num=1であると仮定する.100個のスレッドがここに入り、selectが出てくるバージョン番号はversion=100です.そして直接updateをすると、そのうちの1つだけが先にupdateされ、バージョン番号が更新されます.他の99個は更新時にversionが前回selectのversionに等しくないことに気づき、versionが他のスレッドに修正されたことを示します.では今回のupdate
  • を諦めます
  • redis
  • を利用
    redisの単一スレッドを使用して在庫を事前に削減します.例えば商品は100点あります.ではredisにk,vを格納します.たとえば,ユーザスレッドが入るごとにkey値が1減少し,0に減少すると残りの要求をすべて拒否する.つまり、100個のスレッドだけが後続の操作に入ります.だからきっと売れ残りは起こらない
    3.まとめ
  • の第2の方法は、sql文を実行する前にnum数が0より大きいかどうかのビジネスロジック判断を追加し、ロックを追加する必要があります.
  • 実際には、第1の方法と第2の2つの方法で超販売を解決する方法にも微細な違いがある.
  • 在庫数が2の場合、2つのスレッドを考慮します.
  • が第1の方法であれば、両方のスレッドが正常に実行されます.
  • 第2の方法で、第1のスレッドがトランザクションをコミットする前に、第2のスレッドも同じsqlを実行してversion値(すなわち、スレッド1とスレッド2が同じversion値を取得した)を取得した場合、この2つのスレッドの間には在庫数を1つ減らして正常に実行できるスレッドが1つしかありません.最終在庫数は0ではなく、1
  • である.