2

との取引がSELECTありますINSERT。並行性の理由から、に追加FOR UPDATEしましたSELECT。ファントム行を防ぐために、SERIALIZABLEトランザクション分離レベルを使用しています。これはすべて、テーブルに行がある場合は正常に機能しますが、テーブルが空の場合は機能しません。テーブルが空の場合、はSELECT FOR UPDATE(排他的な)ロックを行わず、並行スレッド/プロセスはSELECT FOR UPDATEロックされずに同じものを発行できます。

CREATE TABLE t (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  display_order INT
) ENGINE = InnoDB;

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT COALESCE(MAX(display_order), 0) + 1 from t FOR UPDATE;

..

この概念はSQLServerでは期待どおりに機能しますが、MySQLでは機能しません。私が間違っていることについて何か考えはありますか?

編集

display_orderにインデックスを追加しても、動作は変わりません。

4

3 に答える 3

1

これには面白い点があり、両方のトランザクションが実際のロックを取得する準備ができています。トランザクションの 1 つが挿入を実行しようとするとすぐに、ロックが発生します。両方のトランザクションが試行すると、デッドロック とロールバックが発生します。そのうちの 1 つだけが試行されると、ロック待機タイムアウトが発生します。

ロック待機タイムアウトを検出した場合は、ロールバックできます。これにより、次のトランザクションが挿入を実行できるようになります。

したがって、デッドロック例外またはタイムアウト例外が非常に速く発生する可能性が高いと思います。これにより、状況が保存されるはずです。しかし、完全な「シリアル化可能な」状況について言えば、これは事実上、空のテーブルの悪い副作用です。エンジンはすべてのケースで完璧というわけではありません.少なくとも二重トランザクション挿入はできません..

昨日、potsgreSQl のドキュメントで、真のシリアビリティとエンジンのシリアビリティの興味深いケースを送信しました。面白い例です: http://www.postgresql.org/docs/8.4/static/transaction-iso.html#MVCC-SERIALIZABILITY

更新: その他の興味深いリソース: MySQL/InnoDB は真のシリアライズ可能な分離を実装していますか?

于 2011-01-12T13:04:20.513 に答える
0

これはおそらくバグではありません。

異なるデータベースが特定のトランザクション分離レベルを実装する方法は 100% 一貫しているわけではありません。InnoDB は Oracle をエミュレートするためのものでしたが、それでも動作が異なる場合があると思います。

アプリケーションが特定のトランザクション分離モードで非常に微妙なロック動作に依存している場合は、おそらく壊れています。

  • たとえ今は「動く」としても、誰かがデータベースのスキーマを変更すると動かなくなるかもしれません
  • ロックの微妙な部分に依存している場合、コードを保守しているエンジニアがデータベースをどのように使用しているかを理解することはまずありません。
于 2011-01-12T12:59:54.843 に答える
0

このドキュメントを見ましたか: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html

あなたが私に尋ねると、mysqlはそのように使用されるように構築されていません...私の推奨事項は次のとおりです。それを実行できる場合->テーブル全体をロックします。

于 2011-01-12T12:48:35.423 に答える