我目前正在維護幾個項目,處理由以前的開發人員編寫的車輛跟蹤。 我發現有時系統會卡住一分鐘左右,而不是繼續工作,我們一直在試圖找出相當長時間的原因。MySQL併發插入,爲什麼會發生,以及處理它的最佳方法是什麼?
我可以看到「鎖等待超時超標;嘗試重新啓動交易」在error.log中,並在瞬間發生這種情況時,我總是看到兩個查詢像這些在MySQL運行:
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)
這兩個查詢一直運行相同的秒數(所以它們同時開始)。一個是由我維護的項目執行的,另一個是執行類似工作的遺留項目(但我想這沒有什麼區別,因爲即使查詢是從同一項目的不同線程)。
我試圖谷歌,似乎當兩個插入同一張表發生在同一時間,MySQL可能會死鎖。我不明白爲什麼會這樣?爲什麼不把MySQL中的兩個查詢放入隊列中並按隨機順序逐一執行?
我們正在使用的隔離級別是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()方法和前在save()完成時提交併保存。
和遺留項目不使用休眠,它只是使用java.sql.Statement中:
setStatement.execute(FleetManagerSqlHelper.insertIdlingEvent(deviceBinding.getVehicleId(), Long.toString(gpsPositionId)));
什麼是處理這種情況的最好方法?我可以減少innodb_lock_wait_timeout(目前爲50),並在每次發生時都會捕獲TimeoutException,然後重試它直到它完成任務(我甚至看到有人在網上推薦它),但這是否正確?這種情況也可能發生在其他表中,我想,這是否意味着我需要用重試來包圍項目中的所有查詢?
我很感激任何建議,因爲我沒有太多的MySQL經驗,我很困惑這種行爲。
非常感謝!