web-dev-qa-db-ja.com

複数の接続でのトランザクションの動作

InnoDBテーブルを含むMariaDBデータベースがあります。同じデータベースに2つの接続があります。 1つの接続は、大量の作業を取り巻くトランザクションを使用しています。もう1つの接続は、同じデータベース(ただし、トランザクションの作業範囲外)のテーブルを更新して、トランザクションの進行状況を追跡するタスクです。

これはすべて同じスクリプトで行われますが、繰り返しになりますが、1つは実行中の実際のジョブ(トランザクションを含む)ともう1つは、ジョブの進行状況に関するメタ情報を保持するための接続です。

これは、トランザクションの作業が別の接続で行われ、他のテーブルに影響を与えるため、ジョブ追跡レコードがジョブの進行に応じて更新されるように機能すると予想しました(10%、20%、50%など)。ただし、私のテストでは、ジョブのトランザクションがコミットされるまで、ジョブ追跡レコードは更新されません。

私の知る限り、「進行状況監視」接続はトランザクションをまったく使用していないため、デッドロックは発生しません。 「ワーカー」接続はクエリをトランザクションにラップしますが、他の接続はラップしません。

作業の進捗状況に応じて入力する「完了率」フィールドを確認するだけで進捗状況を確認します。操作の順序は次のとおりです。

  1. 接続1:トランザクションを開始する
  2. 接続1:行を追加および更新する
  3. 接続2:更新の進行状況
  4. 接続1:さらに行を追加および更新します。

次に、別のHTTP接続で進行状況値をポーリングして出力していますが、接続1のトランザクションがコミットされるまで更新されません。

ジョブ追跡テーブルをまったく別のデータベースに移動する以外に、私が望む動作を得る方法はありますか?

5
Matt James

他の提案された解決策はどれも私にはうまくいかないようでした。代わりに、「ジョブの進行状況」テーブルをInnoDBからMyISAMに切り替えました。 MyISAMはトランザクションをサポートしていないため、トランザクション中であっても、レコードはすぐにテーブルに書き込まれます。

将来的には、一貫性を保つためにすべてのテーブルをInnoDBに保持する別の方法が大好きですが、これが私のために機能していた唯一の解決策でした。

0
Matt James

表示されているのは、デフォルトの分離設定(REPEATABLE READ)、さらに低い(READ COMMITTED)設定。詳細については、MariaDBとMySQLのドキュメントをご覧ください。

基本的には次のようになります。

1つのトランザクションが書き込んでいるもの、他のトランザクションは読み取れないはずです。 1つのトランザクションがコミットする前ではありません。

トランザクションがデータベースに何かを書き込んでいる場合、書き込みが持続するという保証はありません。トランザクションでエラーが発生し、トランザクションが行ったすべての書き込みがロールバックされる場合があります。だから、あなたが観察するもの

ただし、私のテストでは、ジョブのトランザクションがコミットされるまで、ジョブ追跡レコードは更新されません。

その観点からは正しいです。何かがコミットされるまで、外部から見えるものは何もありません。進行状況は0です。これがトランザクションの分離プロパティです。


この問題には2つの解決策があります。

  • A.「ワーカー」、トランザクション1を進行状況レポートにも使用します。労働者自身よりも、その作業がどれだけ進んでいるのかを知る方が良いでしょうか?

  • B. 2番目の「進行状況レポート」接続では、最も低い分離設定(READ UNCOMMITTED):

    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
    

    これで、この接続からのトランザクションは「ダーティリード」を実行できます。つまり、最初のトランザクションからのコミットされていない書き込みを確認し、(コミットされていない)進行状況を正しく報告します。

3
ypercubeᵀᴹ

Connection 2の巨大なトランザクションが1つある可能性があります。

「3.接続2:更新の進行状況」は、それ自体に対するトランザクション内にある必要があります。最も簡単なのは、接続2でBEGINを使用せず、autocommit = 0を設定することです。

これにより、Connection 2はMyISAMとほぼ同じになります。

0
Rick James