ホームページ  >  に質問  >  本文

MySQL の同時ワーカー スレッドによるアトミックな読み取りと更新

MySQL テーブルに対して同時に読み書きできるワーカーが複数あるとします (例: jobs)。各ワーカーのタスクは次のとおりです:

  1. 最も古い キューに入れられた ジョブ
  2. ステータスを RUNNING
  3. に設定します
  4. 対応するIDを返します。

ワーカーがステップ #1 を実行するとき、適格なジョブが 存在しない可能性があることに注意してください (つまり、QUEUED)。

これまでのところ、次の疑似コードがあります。ステップ #1 でジョブが返されない場合は、(

ROLLBACK) トランザクションをキャンセルする必要があると思います。以下のコードでこれを行うにはどうすればよいでしょうか? ああああ

P粉239164234P粉239164234303日前439

全員に返信(2)返信します

  • P粉536909186

    P粉5369091862023-12-22 09:14:00

    あなたが何を望んでいるのかは明確ではありません。しかし、あなたのタスクが次の QUEUED ジョブを見つけることであるとします。ステータスを RUNNING に設定し、適切な ID を選択します。

    シングルスレッド環境では、コードをそのまま使用できます。選択した ID をアプリケーション コードの変数に抽出し、WHERE 句の UPDATE クエリに渡します。 write ステートメントは 1 つだけなので、トランザクションも必要ありません。これを SQLscript で真似ることができます。

    これがあなたの現在のステータスであると仮定します:

    リーリー

    次のキューに入れられたジョブ (id=2) を開始したいと考えています。

    リーリー

    あなたは得ます

    リーリー

    最後の選択から開始します。テーブルのステータスは次のようになります:

    リーリー

    DB Fiddle で見る

    ジョブを起動するプロセスが複数ある場合は、FOR UPDATE を使用して行をロックする必要があります。ただし、LAST_INSERT_ID() を使用すると、この状況を回避できます。

    上記のステータスから開始すると、ジョブ 2 はすでに実行中です:

    リーリー

    次のものが得られます:

    リーリー

    新しいステータスは次のとおりです:

    リーリー

    DB Fiddle で見る

    UPDATE ステートメントがどの行にも影響を与えなかった (キューに入れられた行がない) 場合、

    ROW_COUNT()0 になります。

    私が気づいていないリスクがいくつかあるかもしれませんが、それは私の実際のアプローチ方法でもありません。むしろ、より多くの情報を

    jobs テーブルに保存したいと考えています。簡単な例: リーリー ###そして### リーリー

    現在実行中のジョブは特定のプロセスに属しており、

    を使用するだけで選択できます。 リーリー

    もっと知りたいかもしれません - 例:

    queued_at

    started_atfinished_at

    返事
    0
  • P粉635509719

    P粉6355097192023-12-22 00:24:50

    今週、私はあなたのケースと非常によく似たものを実装します。複数のワーカー。それぞれが一連の行の「次の行」を取得して作業します。

    疑似コードは次のとおりです:

    リーリー

    FOR UPDATE を使用することは、競合状態 (つまり、複数のワーカーが同じ行を取得しようとすること) を回避するために重要です。

    SELECT ... INTO の詳細については、https://dev.mysql.com/doc/refman/8.0/en/select-into.html を参照してください。

    返事
    0
  • キャンセル返事