悲觀鎖與樂觀鎖

悲觀鎖

1、使用場景:

悲觀鎖可以作爲分佈式鎖的一種實現方式,即你某些業務想在高併發的場景下仍被單機執行時,可以在業務代碼執行前,先去獲取某行數據的悲觀鎖,執行業務完成後釋放鎖(commit or rollback),當你還沒有釋放鎖之前,如果有其他線程執行進來且要獲取相同表相同行數據的悲觀鎖,肯定是獲取失敗的,會拋出異常,而不會去執行業務代碼。

 

2、悲觀鎖的核心實現:

select id from table where ... for  update  nowait

  1. 此語句如果會把所有符合條件的行鎖住,如果沒有where條件會鎖整張表,如果查詢條件獲取到的行數據爲空,則不會鎖住行數據;
  2. 一旦行數據被這樣鎖住了,如果獲取悲觀鎖的當前事務還沒有commit,那麼下一個獲取悲觀鎖的事務一定是失敗的;
  3. 如果鎖用完了,需要釋放 (即事務的 commit 或 rollback ) 。mybatis框架會自動commit,即在獲取完悲觀鎖以後立即就commit了,而沒有等到業務執行完才 commit,在高併發時都能獲取悲觀鎖成功。所以需要使用編稱式事務來替代 @Transacional
  4. nowait表示:不會被阻塞,如果獲取悲觀鎖失敗,直接拋異常而不必等待。

 

3、測試1

測試環境:oracle數據庫 + mybatis

釋放悲觀鎖,需要執行 commit 。

4、測試2

 

5、代碼實現

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

        TransactionStatus status = null;
        try {
            //開啓編稱式事務
            status = txManager.getTransaction(new DefaultTransactionDefinition());
            //獲取悲觀鎖
            funcScheduleDefService.forUpdateNoWait(monthendConfirmDTO.getDid(), function, monthendConfirmDTO.getStatDate());
        } catch (Exception e) {
            //獲取鎖失敗,回滾事務
            txManager.rollback(status);
            return null;
        }

        。。。添加悲觀鎖成功,執行業務邏輯


        //執行業務完成,提交事務,釋放鎖
        txManager.commit(status);
        

 

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