首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 靜態唯讀欄位搭配靜態建構函式:編譯期一次性載入資料提升效能模式

     編輯:關於C#

對於「幾乎不變更」的參考資料 (如縣市代碼、幣別、產品分類),每次請求都查詢資料庫是嚴重浪費。本文介紹利用 static readonly 欄位 + static constructor 在**應用程式域啟動時**一次性從資料庫載入到記憶體,後續存取零資料庫開銷。

核心原理

  • static readonly:欄位只能在宣告或靜態建構函式指派,保證不可變性。
  • static constructor:在**第一次存取該類別的任何靜態/實例成員前**自動執行**一次**,執行緒安全由 CLR 保證。
  • 資料載入發生在**應用程式啟動階段** (或第一次使用時),之後純記憶體存取。

實作範例:證書類型快取


using System;
using System.Collections.Generic;
using System.Data;

public static class CertificateCache
{
    // 公開靜態唯讀集合,供全系統直接存取
    public static readonly IReadOnlyList CertificateTypes;
    public static readonly IReadOnlyDictionary> CertificateDictionary;

    // 資料存取介面 (可注入測試用 Mock)
    private static readonly ICertificateRepository _repository = RepositoryFactory.CreateCertificateRepository();

    // 靜態建構函式:CLR 保證只執行一次,執行緒安全
    static CertificateCache()
    {
        // 1. 載入所有證書類型
        var types = _repository.GetAllCertificateTypes();
        CertificateTypes = types.AsReadOnly();

        // 2. 依類型分組載入明細,建立字典
        var dict = new Dictionary>();
        foreach (var type in types)
        {
            var items = _repository.GetItemsByTypeId(type.Id);
            dict[type.Id] = items.AsReadOnly() as List; // 簡化轉型
        }
        CertificateDictionary = dict.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value);
    }

    // 供管理工具呼叫:重新載入 (需重新啟動應用程式域或重新部署)
    public static void Refresh()
    {
        // 靜態欄位無法重新指派,實際上需重啟 AppDomain / IIS / 容器
        // 此處僅示意,實際可改用非 readonly 靜態欄位 + 鎖定實作熱重載
        throw new NotSupportedException("靜態快取需重啟應用程式才能更新。請參考熱重載模式。");
    }
}

// 使用方式:零資料庫查詢
public class CertificateService
{
    public IEnumerable GetItemsByType(int typeId)
    {
        if (CertificateCache.CertificateDictionary.TryGetValue(typeId, out var items))
            return items;
        return Enumerable.Empty();
    }
}

優缺點分析

優點缺點
極致效能:後續存取純記憶體,無鎖、無 IO 資料更新需**重啟應用程式** (IIS Reset / 容器重啟 / 部署新版)
程式碼極簡:無快取過期、淘汰、同步複雜度 啟動時間變長 (資料量大時明顯)
CLR 保證執行緒安全、單次執行 不適合頻繁變動資料 (如庫存、即時價格)
型別安全:強型別集合,編譯期檢查 單元測試難以隔離 (靜態相依),建議搭配 Repository 介面抽象

適用場景判斷清單

  • [ ] 資料**極少變動** (月/年級異動,如行政區劃、幣別、固定代碼表)
  • [ ] 資料量**適中** (萬筆以內,記憶體佔用可接受)
  • [ ] 系統**可容忍重啟部署** 來更新資料
  • [ ] 存取頻率**極高** (每請求多次、高併發)

若以上全勾,此模式為最佳選擇;否則請考慮 MemoryCache、IDistributedCache (Redis) 等支援過期/更新機制的快取方案。

進階:支援熱重載的改良版 (非 readonly + ReaderWriterLockSlim)


public static class HotReloadCache
{
    private static volatile IReadOnlyDictionary _cache;
    private static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    private static readonly Func> _loader;

    static HotReloadCache(Func> loader)
    {
        _loader = loader;
        Reload();
    }

    public static IReadOnlyDictionary Data
    {
        get
        {
            _lock.EnterReadLock();
            try { return _cache; }
            finally { _lock.ExitReadLock(); }
        }
    }

    public static void Reload()
    {
        var newData = _loader();
        _lock.EnterWriteLock();
        try { _cache = newData; }
        finally { _lock.ExitWriteLock(); }
    }
}

此版本支援運行時呼叫 Reload() 更新資料,無需重啟,適合「偶爾變動但需高效能讀取」的場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved