2016-11-21 25 views
0

我目前正在維護幾個項目,處理由以前的開發人員編寫的車輛跟蹤。 我發現有時系統會卡住一分鐘左右,而不是繼續工作,我們一直在試圖找出相當長時間的原因。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經驗,我很困惑這種行爲。

非常感謝!

回答

0

我們已將事務隔離級別更改爲READ-COMMITTED,它似乎已解決問題

相關問題