@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) { /* 業務代碼在該區域 */ }