高併發下緩存與數據庫雙寫不一致解決方案

解決方案

在高併發場景下,數據庫和緩存雙寫不一致狀況,咱們能夠當寫入數據庫後刪除緩存,當查的時候先查緩存,若是緩存爲空再查數據庫,最後寫入緩存,可是這樣仍是存在一個問題。java

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Z0UH9SLx-1613922052987)(assets/image-20210221224231963.png)]

如圖所示,當出現這種狀況時該方案就會出現問題,線程2阻塞一段時間後,又把stock=9有更新到緩存中,而數據庫中的stock=10,下一次查時,會查到緩存中的stock=9git

方案優化

對於這種問題,若是業務場景對數據一致性沒有那麼高,咱們能夠在更新緩存時設置一個過時時間,過時以後緩存也就不存在了,還有一種咱們能夠使用延遲雙刪方案。github

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8pTXbprR-1613922052990)(assets/image-20210221224634975.png)]

間隔的n秒沒有統一的標準,徹底看我的的經驗,因此這種方案仍是存在問題。最佳解決方案時使用分佈式鎖。redis

咱們能夠使用redis讀鎖和寫鎖。咱們使用redisson實現分佈式鎖。數據庫

Redisson

GitHub:https://github.com/redisson/r...緩存

中文文檔:https://github.com/redisson/r...併發

注入RedissonClient對象

@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;
    }
相關文章
相關標籤/搜索