@Transactional 中使用執行緒鎖導致了鎖失效

佳沃發表於2024-07-18

當執行緒A將level設定為99時,此時鎖已經釋放了,但是事務還沒提交!!執行緒B此時可以獲取到鎖並進行查詢,查詢出來的level還是執行緒A修改之前的100,所以出現了併發問題。

解決方案

1、@Transactional單獨一個方法

private Lock lock = new ReentrantLock();
@Transactional
public void test1() {
    // 簡單的select + update 模擬業務場景
    Model model = mapper.choseOne("99");

 // 實現 level -- 操作
    Model updater = new Model();
    updater.setId("99");
    updater.setLevel(model.getLevel() - 1);
    mapper.updateOne(updater);
}

@Autowired
@Lazy
private CommonService commonService;
public void test() {
    try {
        // 加鎖
        lock.lock();
        // 自己注入自己,以使用到其代理類
        commonService.test1();
    } finally {
        lock.unlock(); // 解鎖
    }
}

2、使用程式設計式事務

// service程式碼
private Lock lock = new ReentrantLock();
@Autowired
private PlatformTransactionManager transactionManager;
public void test() {
 try {
     //加鎖
     lock.lock();
     // 程式設計式事務
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        
     // 簡單的select + update 模擬業務場景
     Model model = mapper.choseOne("99");
 
  // 實現 level -- 操作
     Model updater = new Model();
     updater.setId("99");
     updater.setLevel(model.getLevel() - 1);
     mapper.updateOne(updater);
     
  // 在鎖中提交
        transactionManager.commit(status);
 } finally {
       lock.unlock(); // 解鎖
    }
}

相關文章