私は現在、以前の開発者によって書かれた車両追跡を扱ういくつかのプロジェクトを維持しています。 私は、時にはシステムが約1分間立ち往生して仕事を続けることがあることを発見しました。私たちはかなり長い間その理由を見つけようとしてきました。MySQL同時挿入、なぜそれが起こり、それに対処する最良の方法はありますか?
私が見ることができる「ロック待ちタイムアウトを超過し、トランザクションを再起動してみてください」これが発生したとき、私はいつもこれらは、MySQLで動作しているような2つのクエリを参照のerror.logにし、瞬間に:
Insert into idling_events (gps_position_id, vehicle_id) values (23083665777 ,'46881')
と
をinsert into idling_events (gps_position_id, vehicle_id, created_at, updated_at) values (23083665761, null, null, null)
両方のクエリは常に同じ秒数で実行されていたため、同時に開始しました。 1つは私が維持しているプロジェクトで実行され、もう1つは同様の仕事をしているレガシープロジェクトに当たっています(しかし、それは何の違いもありません。同じことはおそらくクエリーが同じプロジェクトの異なるスレッド)。
私はGoogleにしようとしましたが、同じテーブルに2つの挿入が同時に発生した場合、mysqlはデッドロックされる可能性があります。どうしてこのようなことが分かりませんか?なぜmysqlは2つのクエリをキューに入れず、順番に1つずつ実行しないのですか?
私たちが使用している隔離レベルはREPEATABLE READです。私はStackoverflowでREAD COMMITTEDに変更するいくつかの推奨事項を見ましたが、わたしは理解しているように、私たちの問題を解決し、レプリケーションを破るかもしれないとは確信していません。
テーブルの構造は以下の通りである:
id bigint(14) unsigned, not null, primary key, auto_increment
gps_position_id bigint(14) unsigned, not null, key: mul
vehicle_id int(11), can be null, key: mul
created_at datetime, can be null
updated_at datetime, can be null
テーブルはInnoDBテーブルを使用しています。 この表にはgps_position_indexとvehicle_indexもあります。問題がテーブルにインデックスを持っているという事実に関連しているのだろうか?
我々はアイドリングのイベントを保存するために使用する方法がGenericHibernateDaoImpl内)(保存している:私は理解して、
@Override
public T save(T item) {
factory.getCurrentSession().saveOrUpdate(item);
return item;
}
クラスGenericHibernateDaoImplは@Transactionalディレクティブを持っているので、トランザクションは、()メソッドおよび保存呼び出す前に開いていますsave()が終了するとコミットされ、保存されます。
とレガシープロジェクトは何の休止状態を使用しない、それだけでjava.sql.Statementのを使用しています:
setStatement.execute(FleetManagerSqlHelper.insertIdlingEvent(deviceBinding.getVehicleId(), Long.toString(gpsPositionId)));
このような状況に対処するための最善の方法は何ですか?私はinnodb_lock_wait_timeout(現時点では50)を減らして、起こるたびにTimeoutExceptionをキャッチし、それがジョブを作るまでそれを再試行します(私は誰かがオンラインで推薦するのを見たこともあります)。この状況は他のテーブルでも起こる可能性があります。つまり、プロジェクト内のすべてのクエリを再試行で囲む必要があるのでしょうか?
私は多くのMySQLの経験がなく、この動作によって非常に混乱しているので、助言をいただければ幸いです。
ありがとうございました!