java中鎖與@Transactional同時使用導致鎖失效的問題


示例代碼

  @Transactional
    public void update(int id) {
        boolean lock = redisLock.lock(id);
        if (!lock) {
            throw new RuntimeException("當前人數過多,請稍后再試");
        }
        /*
          業務代碼在該區域
         */
        redisLock.unlock(id);
    }

在上面的代碼中,我們同時使用了@transactional和redis分布式鎖(其他鎖同理,比如synchronized同步鎖也會出現這個問題)

問題分析

  上面這個例子是無法保證數據的一致性.由於spring的aop,會在update方法之前開啟事務,之后再加鎖,當鎖住的代碼執行完成后,再提交事務,因此鎖住的代碼塊執行是在事務之內執行的,可以推斷在代碼塊執行完時,事務還未提交,鎖已經被釋放,此時其他線程拿到鎖之后進行鎖住的代碼塊,讀取的庫存數據不是最新的。

解決方法

  我們可以在update方法之前就加上鎖,在還沒有開事務之前就加鎖,那么就可以保證線程的安全性,從而不會出現臟讀和數據不一致性等情況.

   @RequestMapping("/execute")
    public void execute(int id) {
        boolean lock = redisLock.lock(id);
        if (!lock) {
            throw new RuntimeException("當前人數過多,請稍后再試");
        }
        service.update(id);
        redisLock.unlock(id);
    }
   @Transactional
    public void update(int id) {
        /*
          業務代碼在該區域
         */
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM