天天看點

記一次開發BUG Sharding讀寫分離事務下使用select for update導緻死鎖

死鎖場景

select for update 為悲觀鎖,隻有目前會話才能過去到鎖,其他事務通路加鎖資料會被阻塞。

以下代碼無實際邏輯,隻做示範…

代碼如下:

@Transactional
public void test() {
	userService.selectByIdForUpdate(1L);
    userService.increaseAmountById(1L, 10);
}
           

使用Sharding JDBC讀寫分離時,導緻死鎖。

死鎖原因

使用Sharding JDBC後,目前事務第一個寫之前的所有讀操作都會優先讀取從庫,而事務内第一個寫以後的讀寫操作都隻會操作主庫。

根本原因:查詢和更新不是同一個會話,導緻死鎖。即便是select for update,也會操作從庫,導緻讀取和修改不在同一個會話。但是由于是開發環境,主從為同一個資料庫,讀方法加鎖後,寫方法擷取鎖失敗,事務不送出,讀不釋放鎖,寫擷取不到鎖,導緻死鎖。

解決方法

  1. 在需要指定主庫查詢前,加一行代碼,指定隻能從主庫讀取資料:

    HintManager.getInstance().setMasterRouteOnly();

  2. 在查詢之前執行一次主庫更新,無業務需求不建議使用。

代碼如下

@Transactional
public void test() {
    HintManager.getInstance().setMasterRouteOnly();
    userService.selectByIdForUpdate(1L);
    userService.increaseAmountById(1L, 10);
}