2

現在、アプリケーションのテスト動作を改善しようとしています。

テストは現在、ネストされたトランザクション内で開始されます。テスト スイートは実際のトランザクションを開始し、テスト ケースはそれぞれネストされたセーブポイントを作成します。

テスト ケースが終了すると、セーブポイントは単純に解放され、元のデータが復元されます。スイートが終了すると、トランザクションはロールバックされます。

(テーブルで切り捨てを使用することはオプションではありません。シード データが大きすぎて、中央テストと同時テストが妨げられるためです)

これはうまくいきます。

トランザクションが同時に実行されると、トランザクションはお互いをテーブルからロックアウトする傾向があります。これは、一意のキーを持つテーブルでさらに発生します (2 つのトランザクションのいずれかですべてのテストが失敗します)。

トランザクション状態「READ COMMITTED」、「READ UNCOMMITED」、およびデフォルトの「REPEATABLE READ」でこれを実行しようとしました。

READ UNCOMMITTED により、重複キーの問題が発生しました。READ COMMITTED にはロック/デッドロックの問題があります REPEATABLE READ にはロック/デッドロックの問題があります (上記と同じ)

さらに、次のオプションを適用しようとしました: innodb_autoinc_lock_mode=2

> -- mysql command line
> SET SESSION binlog_format=ROW
> SET SESSION innodb_table_locks=OFF

最後のパラメーターは、いくつかのロックの問題を解決しました。「ロック待機タイムアウト」とデッドロックの問題は残ります。

個別のトランザクションを互いに真に独立させるソリューションはありますか?

更新:さらなるテストが示した:デッドロックは現在、一意のキーを持つテーブルでのみ発生します。セッション 1 で既にこれらのキーが使用されていると思われるため、行ロックの犠牲者になる可能性があります。

mysql サーバーのバージョン: 5.5.15

編集:ワークフローの例を追加すると、問題がより明確になります(タイプミスや軽微な構文エラーが含まれている可能性があります。それらは重要ではありません)。異なる接続 異なる意図

> create table foo (
>   `id` int(11) auto increment,
>   `name` varchar(255),
>   PRIMARY KEY id,
>   UNIQUE KEY `name`(`name`)
> ) ENGINE=InnoDb;
> insert into foo(name) values ('bar');

> begin;                                       -- connection 1, transaction 1
>   begin;                                     -- connection 2, transaction 1
> savepoint t_1;                               -- connection 1, savepoint within transaction 1
>   savepoint t_1;                             -- connection 2, savepoint within transaction 1
> select count(*) from foo;                    -- connection 1, number of entries in foo, should be 1
> insert into foo('name') values ('meh');      -- connection 1, insert into foo the unique fixed value 'meh', should work
>   select count(*) from foo;                  -- connection 2, number of entries in foo, should be 1
>   insert into foo('name') values ('meh');    -- connection 2, insert into foo the unique fixed value 'meh', should work
> select count(*) from foo;                    -- connection 1, number of entries in foo, should be 2
>   select count(*) from foo;                  -- connection 2, number of entries in foo, should be 2
> rollback to savepoint t_1;                       -- connection 1, discard everything up until savepoint t_1
> rollback;                                    -- connection 1, rollback
>   rollback to savepoint t_1;                     -- connection 2, discard everything up until savepoint t_1
>   rollback;                                  -- connection 2, rollback

この例では、私が望むトランザクション分離のテストと見なす必要があるのはすべてです。

4

1 に答える 1

0

テストを同時に実行しようとしているように思えます。そのため、同時クエリが実行されています。その場合は、単にロックが発生しているという点で 100% 正しいと思います。

テストが終了したときにロールバックされることを意図した目的で、開いているトランザクション (つまり、実行時間の長いテスト) がある場合、他の書き込みを行うのに多くの問題が発生し、同じ行/テーブルに対していくつかの読み取りが行われる可能性があります。他のテストの一部。あなたの最善の策は、おそらくすべてを順番に実行することです。

あなたが経験している重複キーの問題は、READ UNCOMMITTED を使用するときに私が予想するものと一致しています。

于 2013-01-27T00:14:20.430 に答える