博客 / 詳情

返回

緩存讀寫代碼邏輯的正確姿勢

緩存通常用於提高數據訪問的效率。一般來説,緩存讀取和寫入的邏輯遵循“先從緩存取,取不到再從數據庫獲取並寫回緩存”的原則。為了避免多個線程同時修改緩存數據,我們需要加鎖來保證數據一致性。

邏輯概述

  1. 讀取緩存:緩存命中直接返回。
  2. 緩存未命中:加鎖,然後再次讀取緩存,緩存命中直接返回。
  3. 緩存還是未命中:執行數據庫查詢並更新緩存。
  4. 返回數據。

代碼大致這樣寫

public class CacheService
{
    private readonly ICache _cache;
    private readonly IDatabase _database;
    private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

    public CacheService(ICache cache, IDatabase database)
    {
        _cache = cache;
        _database = database;
    }

    public string GetDataFromCacheOrDb(string key)
    {
        // 1. 嘗試從緩存獲取數據
        var data = _cache.Get(key);
        if (data != null)
        {
            return data;  // 緩存命中,直接返回
        }

        // 2. 如果緩存中沒有,嘗試加鎖並獲取數據
        _semaphore.Wait();

        try
        {
            // 再次檢查緩存(可能另一個線程已經填充了緩存)
            data = _cache.Get(key);
            if (data != null)
            {
                return data;  // 緩存命中,直接返回
            }

            // 3. 從數據庫獲取數據
            data = _database.Query(key);

            // 4. 將數據寫入緩存
            _cache.Set(key, data);

            return data;
        }
        finally
        {
            // 釋放鎖
            _semaphore.Release();
        }
    }
}

關鍵是緩存在鎖前和鎖後都要讀一次,為了減少多個線程都在等待鎖的情況,同時進來查詢數據庫寫緩存。

分佈式情況下會更復雜一些

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.