7

これらの条件下で sql で競合状態が発生する可能性はありますか?

この SQL 更新を 1 つのスレッドで実行する場合、それをステートメント 1 と呼びます。

Update Items
Set Flag = B
where Flag = A;

そして、別の call it ステートメント 2 で実行されているこの SQL 更新:

Update Items
Set Flag = C
where Flag = A;

各スレッドがフラグが A に等しい同じレコードを読み取り、独自の値でレコードを書き込むことは可能ですか? ステートメント1が最初にそれを書き、次にステートメント2がそれを書くことができるように、またはその逆ですか?

この質問に対する答えは、データベースがいつ更新を排他的にロックするかによって異なります。レコードを見つける前に発生しますか、それともレコードを見つけて where 句を評価した後に発生しますか?

4

4 に答える 4

5

まず、3つのロックコンテキストがあります。

  • データベースレベルのロック
  • テーブルレベルのロック
  • 行レベルのロック

次に、4つのロックモードがあります。

  • IX
  • バツ
  • S

IXおよびISロックは「意図的な」ロックです。これらのロックは、他のタイプのロックを取得する前に保持されます。Xロックは排他的(書き込み)ロックであり、Sロックは共有(読み取り)ロックです。

ロック(IX、IS、X、またはS)ロックは、任意のコンテキストレベルで取得できます。データベースレベルでのXロックは、たとえばデータベース内の他のすべての操作をブロックします。これはSQLliteが取るタイプのロックです。読み取り中にデータベース全体に対してSロックが取得され、書き込み中にデータベース全体に対してXロックが取得されます。書き込みは、Sロックが完了するのを待ち、書き込みロックが解放されるまで、新しいSロックとXロックをブロックします。これにより、シリアル化可能な分離トランザクションレベルが提供されます。

MySQLの場合、ロックはストレージエンジンに依存します。MyISAMは、テーブル全体(セット)に対してXおよびSロックを取得します。Xロックは、既存のSまたはXロックを待機し、新しいロックをブロックします。新しいXロックはキュー内でより高い優先順位が与えられ、新しいSロックよりも先に移動します。この動作は、LOW_PRIORITY_UPDATESを設定することで変更できます。これにより、書き込みの優先順位が下げられて読み取りが優先されるため、書き込みが不足する可能性があります。

MySQLでは、「FLUSH TABLESWITHREADLOCK」を使用してデータベース全体のXロックを取得することができます。

InnoDBは、インデックスの読み取りを介して行が検出されると、行をロックします。InnoDBはインデックスレコードをロックし、インデックスレコードがトラバースされるときにレコードをロックします。InnoDBは、「ギャップ」ロックと呼ばれる特別なロックを使用して、REPEATABLE-READトランザクション分離レベルを確保します。ロックはインデックスエントリで保持されるため、テーブルがUPDATEクエリに対して適切にインデックス付けされていない場合、多くの行がロックされます。InnoDBは、通常のSELECTクエリに対してSロックを作成しないことに注意してください。一貫性のあるスナップショットのために、行レベルのロックではなく、行のバージョン管理を使用します。

Xロックを取得する場合、データベースはデッドロックを検出する必要があります。次のことを考慮してください。

>connection 1
start transaction;
update T set c = c + 1 order by id asc;

>connection 2
start transaction;
update T set c = c - 1 order by id desc;

行ロックモデルでは、これら2つのステートメントの両方を正常に完了することはできません。最初のものは、2番目が保持するロックを取得するために永遠に待機し、その逆も同様です。データベースは、ロールバックする接続の1つを選択します。InnoDBは、変更の数が最も少ない接続を選択します。MyISAMは、最初にロックを取得した接続に対してテーブル全体をロックし、最初の接続が完了した後に2番目の接続が実行されます。

あなたが与えた簡単な例は、任意のコンテキスト(データベース、テーブル、または行)でのXロックによって解決されます。2つの接続がまったく同じタイプで始まり、両方が同じ行を更新しようとする2つの更新を実行している場合、両方がXロックを取得しようとします。Xロックを取得できる接続は1つだけです。どちらがロックを取得するかを正確に決定することはできません。他の接続は、Xロックを取得できるようになるまで、ロックが解放されるまで待機する必要があります。行がDELETEまたはUPDATEによってロックされた場合、データベースにロックするものが残っていないため、ウェイターは待機後にロックを取得しなくなる可能性があることに注意してください。

この例では、Xロックを取得する最初のUPDATEと2番目のUPDATEがXロックを待機し、最終的に実行されますが、どの行とも一致しません。

于 2012-08-04T00:12:10.933 に答える
0

このシナリオでは、INSERT、UPDATE、または DELETE などのデータ変更操作に使用される排他ロックが使用されます。

排他ロックにより、同じリソースに対して同時に複数の更新を行うことができなくなります。

このシナリオでは、競合状態は発生しません。

複数のテーブルを含むより複雑なシナリオがある場合は、競合状態またはデッドロックが発生する可能性があります。これを回避するには、クエリを単純化して分離するなど、さまざまな方法があります。

クエリにヒントを適用して、使用するロックの種類を SQL に伝えることもできます。

http://msdn.microsoft.com/en-us/library/aa213026(v=sql.80).aspx

于 2012-08-03T22:28:27.217 に答える
0

ロックについて読む必要があるようです。SQL サーバーには複雑なロジック セットがあり、更新が必要になると推定される行数に基づいて、テーブルまたは行レベルのロックを実行します。何を実行するかを具体的に指定しない限り、クエリごとに異なる場合もあります。通常、テーブルの小さなサブセットを変更する場合、行レベルのロックが選択されます。

SQL Server は ACID を念頭に置いて設計されているため、実際のデータ更新を実行する前にログに変更を書き込みます。これにより、失敗した更新をロールバックし、クエリ間の一貫性を確保できます (質問など)。ダーティ リードを実行してロックの問題を回避できますが、SQL Server が挿入、更新、または削除されたレコードをロックするのを防ぐことはできません。

SQL サーバーのロック

編集: これは ACID に関する記事です。 ACID - ウィキペディア

于 2012-08-03T22:30:42.713 に答える
0

すべての SQL データベースは、このような衝突が発生しないことをほぼ保証しています。"いつ" ロックが発生するかは、ロックがテーブル、パーティション、ページ、または行レベルのいずれであるかによって異なります。または、データベースでそのようなロックをオフにしているかどうか。

同時更新ステートメントがあり、複数の行が更新されている場合に起こりうることは、最初の行で更新される行と、2 番目の行で更新される行があるということです。

一般に、where 句は、行セットを選択し、行を 1 つずつロックし、更新してロック解除するために評価されると考えています。ただし、これはロックの種類によって異なります。この場合、上記のシナリオでは、値が反転して続行されます。

この状況が懸念される場合は、テーブル レベルのロックを使用して、同時更新要求が処理されているときにシリアル化を強制します。

于 2012-08-03T22:40:39.000 に答える