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

示例代碼

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

<small>在上面的代碼中,咱們同時使用了@transactional和redis分佈式鎖(其餘鎖同理,好比synchronized同步鎖也會出現這個問題)</small>redis

問題分析

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

解決方法

  咱們能夠在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) {
        /*
          業務代碼在該區域
         */
    }
相關文章
相關標籤/搜索