在高併發場景下,數據庫和緩存雙寫不一致狀況,咱們能夠當寫入數據庫後刪除緩存,當查的時候先查緩存,若是緩存爲空再查數據庫,最後寫入緩存,可是這樣仍是存在一個問題。java
如圖所示,當出現這種狀況時該方案就會出現問題,線程2阻塞一段時間後,又把stock=9有更新到緩存中,而數據庫中的stock=10,下一次查時,會查到緩存中的stock=9git
對於這種問題,若是業務場景對數據一致性沒有那麼高,咱們能夠在更新緩存時設置一個過時時間,過時以後緩存也就不存在了,還有一種咱們能夠使用延遲雙刪方案。github
間隔的n秒沒有統一的標準,徹底看我的的經驗,因此這種方案仍是存在問題。最佳解決方案時使用分佈式鎖。redis
咱們能夠使用redis讀鎖和寫鎖。咱們使用redisson實現分佈式鎖。數據庫
GitHub:https://github.com/redisson/r...緩存
中文文檔:https://github.com/redisson/r...併發
@Bean public RedissonClient redissonClient(){ Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); return Redisson.create(config); }
@GetMapping("read") public String read(){ RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(RedisConstant.READ_WRITE_LOCK); //讀以前加讀鎖,讀鎖的做用就是等待該lockkey釋放寫鎖之後再讀 RLock rLock = readWriteLock.readLock(); try { rLock.lock(); String uuid = redisTemplate.opsForValue().get("uuid"); return uuid; }finally { rLock.unlock(); } }
@GetMapping("write") public String write() throws InterruptedException { RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(RedisConstant.READ_WRITE_LOCK); //寫以前加寫鎖,寫鎖加鎖成功,讀鎖只能等待 RLock rLock = readWriteLock.writeLock(); String s = ""; try { rLock.lock(); s = UUID.randomUUID().toString(); Thread.sleep(10000); redisTemplate.opsForValue().set("uuid",s); }finally { rLock.unlock(); } return s; }