現在、アプリケーションのテスト動作を改善しようとしています。
テストは現在、ネストされたトランザクション内で開始されます。テスト スイートは実際のトランザクションを開始し、テスト ケースはそれぞれネストされたセーブポイントを作成します。
テスト ケースが終了すると、セーブポイントは単純に解放され、元のデータが復元されます。スイートが終了すると、トランザクションはロールバックされます。
(テーブルで切り捨てを使用することはオプションではありません。シード データが大きすぎて、中央テストと同時テストが妨げられるためです)
これはうまくいきます。
トランザクションが同時に実行されると、トランザクションはお互いをテーブルからロックアウトする傾向があります。これは、一意のキーを持つテーブルでさらに発生します (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
この例では、私が望むトランザクション分離のテストと見なす必要があるのはすべてです。