記錄項目中的鎖等待超時Lock wait timeout exceeded——事務與索引

問題描述

項目中突然報錯,主要是兩個,一個是任務腳本執行時間過長,另一個是鎖等待時間過長,如下

Lock wait timeout exceeded; try restarting transaction

該任務腳本用於做多個表之間的數據同步,同時,項目中還有多個腳本和其他代碼有可能對錶數據進行操作,產生鎖。有兩個表的數據量爲百萬級別,且數據項也比較多。

如果對死鎖和鎖等待不是很瞭解,可以快速跳到下面的鏈接,理解一下什麼是鎖等待,以及可能造成的原因。死鎖和鎖等待

問題分析

首先,先放出來這部分的僞代碼吧(便於理解)

void method(){
	事務開始;
	while(true) {
		List<ObjectA> list1 = 從A表按照條件拿出100條數據;
		if(list1爲空){ //如果爲空,表示數據已經處理完畢,結束
			return;
		}
		
		//依次操作ObjectA數據
		for(ObjectA objectA: list1) {
			刪除A表數據;
			與B表數據合併,並更新對應的數據;
			同步C表數據;
		}
	}
	事務結束;
}

原因主要是事務加的位置有問題,並且數據表沒有對應索引,導致更新時間過長。

任務執行時間過長

這個主要是因爲更新數據的時候缺少索引,數據量比較大時,查找對應數據的時間比較長。這個可以通過數據庫sql語句執行時間分析出來,因爲我們單位有大數據平臺,通過大數據平臺的分析,找到執行時間最長的幾條sql分析一下就可以了。如果沒有相關的平臺,建議在一些數據量比較大的表的查詢和更新操作前後加日誌記錄,方便對sql執行情況進行分析。

鎖等待時間過長

這個是事務和索引共同導致的。

在事務執行的過程中,對事務中所有涉及更新/添加的表加鎖,其他進程請求這部分表數據時就會鎖等待。索引缺失導致代碼中每次循環的時候都過長,又對整個循環加上了事務,所以鎖等待的時間就會超時,出現文章開頭的問題。除了數據庫層面加上索引,還需要調整代碼的內容,去掉事務或者優化事務位置。

問題解決

1、數據庫:我們在b表,根據查詢的條件建立了索引。之前平均執行時間爲10min,添加後縮短到1min。

2、代碼,因爲我們業務特點,我們這段代碼,即使更新出現異常,只要依然保留A表數據,就不會對整體業務產生影響。下次腳本執行時就可以補充回來這部分數據,所以我們去掉事務、調整代碼結構並加上一段異常處理,調整後的代碼如下。

void method(){
	while(true) {
		List<ObjectA> list1 = 從A表按照條件拿出100條數據;
		if(list1爲空){ //如果爲空,表示數據已經處理完畢,結束
			return;
		}
		
		//依次操作ObjectA數據
		for(ObjectA objectA: list1) {
			try{
				與B表數據合併,並更新對應的數據;
				同步C表數據;
				刪除A表數據;
			} catch(Exception e) {
				日誌記錄異常;
			} finally {
				日誌記錄執行時間;
			}
		}
	}
}

當然,如果業務場景需要,必須使用事務,也可以把循環內的代碼拿出來,單獨進行事務操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章