ABP VNext + EF Core 二級緩存:提升查詢性能

ABP VNext + EF Core 二級緩存:提升查詢性能 🚀


📚 目錄

  • ABP VNext + EF Core 二級緩存:提升查詢性能 🚀
    • 引言 🚀
    • 一、環境與依賴 🛠?
    • 二、集成步驟 ??
      • 2.1 安裝 NuGet 包
      • 2.2 注冊緩存服務與攔截器
      • 2.3 對特定查詢啟用緩存 🎯
    • 三、緩存依賴與失效 🔄
    • 四、性能對比測試 📈
      • 4.1 測試環境 🖥?
      • 4.2 對比指標 🔥
    • 五、最佳實踐與注意事項 ??
    • 六、高級配置 🧩


引言 🚀

TL;DR ?

  • 集成 EFCoreSecondLevelCacheInterceptor v5.3.1,為 ABP VNext 應用添加跨 DbContext、跨請求的二級緩存,顯著降低重復查詢開銷
  • 幾行配置即可啟用內存或 Redis 緩存,并支持自動失效與手動失效策略 🔄
  • 支持按實體類型或表名緩存,無需手動管理復雜緩存鍵 🛡?
  • 實測:平均響應時間由 ~120 ms 降至 ~15 ms,QPS 從 ~500 提升至 ~3 500,數據庫訪問次數減少至 1 次/秒 📊

關系型數據庫在高并發場景下常見瓶頸包括 CPU、IO 與連接數。EF Core 默認僅在單個 DbContext 生命周期內緩存實體,請求結束后即釋放。引入二級緩存(跨 DbContext、跨請求)可顯著減少重復查詢開銷,緩解數據庫壓力。


一、環境與依賴 🛠?

  • 運行平臺:.NET 6.0 LTS + ABP VNext 6.x

  • EF Core 版本:6.x

  • EFCoreSecondLevelCacheInterceptor:5.3.1

  • 緩存提供者

    • 內存:EFCoreSecondLevelCacheInterceptor.MemoryCache
    • Redis:EFCoreSecondLevelCacheInterceptor.StackExchange.Redis
  • 其他依賴Volo.Abp.EntityFrameworkCore

  • ABP CLIVolo.Abp.Cli v6.x

  • 前提:項目已集成 EF Core 與 ABP 基礎模塊,已配置連接字符串與常規 DbContext

  • 注意:如需在 .NET 7/8 下使用,請升級到 ABP 7.x 或 ABP 8.x 🔄


二、集成步驟 ??

項目啟動
ConfigureServices
注冊緩存服務
配置全局策略
UseMemoryCacheProvider/Redis
CacheAllQueries(...)
Configure
AddInterceptors(SecondLevelCacheInterceptor)
DbContext 工作流程

2.1 安裝 NuGet 包

dotnet add package EFCoreSecondLevelCacheInterceptor --version 5.3.1
dotnet add package EFCoreSecondLevelCacheInterceptor.MemoryCache        # 內存緩存
# 或
dotnet add package EFCoreSecondLevelCacheInterceptor.StackExchange.Redis  # Redis 緩存

2.2 注冊緩存服務與攔截器

在 ABP 模塊(如 MyProjectEntityFrameworkCoreModule)的 ConfigureServices 方法中:

public override void ConfigureServices(ServiceConfigurationContext context)
{// 1. 添加二級緩存服務context.Services.AddEFSecondLevelCache(options =>options.UseMemoryCacheProvider().ConfigureLogging(false)                               // 生產環境關閉日志.UseCacheKeyPrefix("EF_")                              // 統一前綴,便于分區管理.UseDbCallsIfCachingProviderIsDown(TimeSpan.FromMinutes(1)) // 緩存不可用時回退數據庫.CacheAllQueries(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(5)) // 全局緩存所有查詢.AllowCachingWithExplicitTransactions(true)            // 顯式事務中也可緩存); // 2. 注冊 DbContext 并注入攔截器(僅針對 MyDbContext)context.Services.AddAbpDbContext<MyDbContext>(options =>{options.AddDefaultRepositories();});context.Services.Configure<AbpDbContextOptions>(opts =>{opts.Configure<MyDbContext>(config =>{config.DbContextOptions.UseSqlServer(context.Services.GetConfiguration().GetConnectionString("Default")).AddInterceptors(context.Services.GetRequiredService<SecondLevelCacheInterceptor>());});});
}

2.3 對特定查詢啟用緩存 🎯

// 使用全局策略(5 分鐘絕對過期)
var products = await _productRepository.WithDetails().Cacheable().ToListAsync();// 自定義滑動過期 1 分鐘
var recentOrders = await _orderRepository.Where(o => o.CreatedDate > since).Cacheable(CacheExpirationMode.Sliding, TimeSpan.FromMinutes(1)).ToListAsync();

三、緩存依賴與失效 🔄

Cacheable
未命中
命中
觸發攔截
Query
二級緩存
數據庫
返回結果
SaveChanges()/SaveChangesAsync()
自動清理相關緩存
  • 自動失效:攔截所有 SaveChanges()/SaveChangesAsync(),根據受影響表自動清除相關緩存,無需額外配置

  • 批量操作限制:EF Core 的 ExecuteUpdate()ExecuteDelete() 繞過 ChangeTracker,不會觸發緩存失效,需手動清理:

    await context.Blogs.Where(b => b.IsObsolete).ExecuteUpdateAsync(s => s.SetProperty(b => b.IsActive, false));
    _cacheServiceProvider.ClearAllCachedEntries();
    
  • 按類型或表名緩存

    services.AddEFSecondLevelCache(options =>
    {options.UseMemoryCacheProvider().CacheQueriesContainingTypes(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(30),typeof(Product), typeof(Order)).CacheQueriesContainingTableNames(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(30),TableNameComparison.ContainsOnly, "Products", "Orders");
    });
    
  • 手動清理示例:在服務中注入并使用 IEFCacheServiceProvider

    public class ProductAppService : ApplicationService
    {private readonly IEFCacheServiceProvider _cacheServiceProvider;public ProductAppService(IEFCacheServiceProvider cacheServiceProvider){_cacheServiceProvider = cacheServiceProvider;}public void RefreshProductCache(){_cacheServiceProvider.ClearAllCachedEntries();          // 清除所有緩存_cacheServiceProvider.ClearCacheByPrefix("EF_Products"); // 按前綴清理}
    }
    

四、性能對比測試 📈

4.1 測試環境 🖥?

  • 機房環境:Windows Server 2019,Intel Xeon Gold 6248(8 核/16 線程),32 GB RAM
  • 數據庫:SQL Server 2019
  • 數據量:100 萬條訂單記錄
  • 測試工具:自編腳本 + Stopwatch
// 預熱
await WarmUpDbAsync();// 測試 1,000 次請求
var sw = Stopwatch.StartNew();
for (int i = 0; i < 1000; i++)
{await _orderRepository.WithDetails().Cacheable().FirstOrDefaultAsync();
}
sw.Stop();
Console.WriteLine($"Elapsed: {sw.ElapsedMilliseconds} ms");

控制臺輸出示例

Warm-up completed.
Testing 1000 requests...
Elapsed: 15000 ms

聲明:以上測試基于串行腳本,僅對比緩存前后性能變化,實際生產環境下并發吞吐量會更高,讀者可使用 BenchmarkDotNet 進行多線程基準測試,并查看腳本和日志以復現。

4.2 對比指標 🔥

指標無緩存模式啟用二級緩存
平均響應時間~120 ms~15 ms
QPS~500/sec~3 500/sec
DB 訪問次數~10 次/秒~1 次/秒

五、最佳實踐與注意事項 ??

  • 讀多寫少:Cache-Aside 模式僅適合讀多寫少場景,高寫場景慎用
  • 緩存粒度:對超大結果集拆分分頁或按關鍵字段緩存,避免一次性加載過多數據
  • 容量管理:根據業務規模調優 MemoryCache 或 Redis 參數(如內存上限、Eviction 策略),防止 OOM
  • 雪崩/穿透:結合互斥鎖、預熱與空值緩存策略,保障系統穩定性
  • 事務內緩存:顯式事務內查詢默認不緩存,啟用需調用 .AllowCachingWithExplicitTransactions(true)

六、高級配置 🧩

services.AddEFSecondLevelCache(options =>
{options.UseMemoryCacheProvider()// 跳過包含特定 SQL 的查詢緩存.SkipCachingCommands(cmd => cmd.Contains("NEWID()"))// 跳過空結果集的緩存.SkipCachingResults(result =>result.Value == null ||(result.Value is EFTableRows rows && rows.RowsCount == 0))// 避免某些更新命令觸發失效.SkipCacheInvalidationCommands(cmd =>cmd.Contains("UPDATE [Posts] SET [Views]"))// 動態覆蓋某些查詢的緩存策略.OverrideCachePolicy(context =>{if (context.IsCrudCommand) return null; // CRUD 不緩存if (context.CommandTableNames.Contains("posts"))return new EFCachePolicy().ExpirationMode(CacheExpirationMode.NeverRemove);return null;});
});

這些配置取自官方高級示例,可按需組合使用。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91396.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91396.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91396.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

3.1k star!推薦一款開源基于AI實現的瀏覽器自動化插件工具 !

大家好&#xff01;今天&#xff0c;我要給大家介紹一款超實用的開源工具——Chrome MCP Server&#xff01;這款工具不僅能大幅提升我們的工作效率&#xff0c;還能讓AI助手&#xff08;如Claude&#xff09;直接操控瀏覽器&#xff0c;實現自動化操作、內容分析等強大功能。 …

關于 OpenAI 的反思

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

Python爬蟲庫性能與選型對比

Python常用爬蟲庫的優勢對比。這是一個非常實用的問題&#xff0c;很多Python開發者都會面臨選擇合適爬蟲工具的困惑。我根據網絡很多搜索結果&#xff0c;整理出這些信息&#xff0c;為用戶提供一個全面且清晰的對比分析。以下是Python中常用爬蟲庫的核心優勢對比及選型建議&a…

NAT作業

拓撲圖 實驗要求 1.按照圖示配置IP地址&#xff0c;公網地址100.1.1.1/24..較網“說過?,使“掩入到互聯網&#xff0c;私服究的不到公的&#xff0c;使陽接入無三。.私網A通過NAPT&#xff0c;使R1接入到互聯網&#xff0c;私網B通過EASY,IP&#xff0c;使R3接入到互聯網實驗思…

JAVA進階--JVM

一.JVM的概述java語言有跨平臺特點, 寫一次java程序,可以在不同的平臺上運行.(JVM虛擬機的作用)前提條件: 在不同的平臺上安裝不同的虛擬機(虛擬機就是一個翻譯).java--->.class--->不同的虛擬機--->機器碼1.jvm作用:負責將字節碼翻譯為機器碼, 管理運行時內存2.jvm的…

基于Alpine構建MySQL鏡像

文章目錄基于Alpine構建MySQL鏡像一、基礎鏡像選擇與初始化1. 基礎鏡像選型2. 系統初始化二、核心配置構建1. 目錄與權限配置2. 配置文件優化三、安全增強配置1. 密碼策略強化2. 非root運行四、數據持久化與啟動配置1. 數據卷聲明2. 入口腳本優化五、完整Dockerfile示例六、關鍵…

Alamofire 網絡請求全流解析,通俗易懂

Alamofire 網絡請求全流程解析&#xff1a;從發起請求到處理響應 一、請求發起階段&#xff1a;準備你的"快遞" 1. 你告訴Alamofire要發什么"快遞" // 就像告訴快遞員&#xff1a;"我要寄一個包裹給https://api.example.com" AF.request("h…

鏈路聚合技術

鏈路聚合技術 鏈路聚合概述及應用場景 概述 鏈路聚合是把多條物理鏈路聚合在一起&#xff0c;形成一條邏輯鏈路。應用在交換機、路由器、服務器間鏈路&#xff0c;注意了&#xff0c;主機上面不能用鏈路聚合技術分為三層鏈路聚合和二層鏈路聚合鏈路聚合的作用 增加鏈路帶寬提供…

SpringCloud之Zuul

SpringCloud之Zuul 推薦參考&#xff1a;https://www.springcloud.cc/spring-cloud-dalston.html#_router_and_filter_zuul 1. 什么是Zuul Spring Cloud Zuul 是 Netflix 提供的微服務網關核心組件&#xff0c;作為統一的 API 入口&#xff0c;承擔請求路由、過濾、安全控制等…

低精度定時器 (timer_list) 和 高精度定時器 (hrtimer)

Linux 內核提供了兩種主要類型的定時器&#xff0c;以滿足不同的時間精度需求&#xff1a;低精度定時器 (timer_list) 和 高精度定時器 (hrtimer)。它們各有特點和適用場景。下面&#xff0c;我將分別提供它們在內核代碼中的簡化使用示例。1. 低精度定時器 (timer_list) 示例ti…

虛擬機VMware的使用方法

虛擬機VMware的使用方法VMware是全球領先的虛擬化技術提供商&#xff0c;其產品&#xff08;如VMware Workstation Pro&#xff09;允許用戶在單一物理機上運行多個操作系統&#xff08;OS&#xff09;&#xff0c;實現資源高效利用、隔離測試和靈活部署。本文將詳細介紹VMware…

冰島人(map)

#include<bits/stdc.h> using namespace std; struct people { string fat; int sex; }; map<string,people>mp; int pan(string s,string m) { string s1; int i0; while(s!“”) { int y0; s1m; while(s1!“”) { if(s1s&&(i<4||y<4)) return 0; s…

MS Azure Eventhub 發送 AD log 到cribl

1: 首先說一下,Cribl 提供了很多第三方的接口: 先看一下cribl 提供的接口界面: 注意到,上面提供的link 地址是 xxxxx:9093, 不鼠標放到撒謊給你嗎的? 上面,就可以看到了。所以要開的port 一定要把9093 開了,關于全部開的port: What ports do I need to open on the f…

電力名詞通俗解析5:計量系統

## 電網計量系統通俗講解&#xff1a;南網視角下的電力“精算師”想象一下&#xff0c;城市電網如同一個龐大而精密的“能量河流”&#xff0c;千家萬戶、工廠企業都在從中取水&#xff08;用電&#xff09;。如何精確計量每家用了多少“水”&#xff1f;如何確保“河流”輸送中…

關于redis各種類型在不同場景下的使用

Redis 提供了多種數據結構類型,每種類型適用于不同的場景。以下是 Redis 主要數據類型及其典型應用場景的詳細說明: 1. String(字符串) 特點:最簡單的鍵值存儲,值可以是字符串、整數或二進制數據(最大 512MB)。 適用場景: 緩存:存儲用戶會話、網頁內容等(如 SET u…

Vue 3 動態ref問題

目錄 1.問題描述 2.示例代碼 3.原因分析 4.解決方案 5.總結 1.問題描述 在Vue 3項目中&#xff0c;當使用動態ref來引用組件時&#xff0c;刪除組件后發現ref對象中對應的key仍然存在&#xff0c;只是值變為null&#xff0c;而不是完全刪除該key。 在一個可拖拽的卡片列表…

lazyvim恢復gt鍵

好的&#xff01;下面是一個完整的 LazyVim 鍵位配置 patch&#xff0c;將 gt / gT 恢復為 “切換標簽頁&#xff08;tab page&#xff09;” 的原始行為&#xff0c;同時保留原本 buffer 切換功能在其他鍵位上&#xff08;比如 / &#xff09;。 ? ? 恢復 gt 為 Tab 切換&a…

React Native 在 Web 前端跨平臺開發中的優勢與實踐

React Native 在 Web 前端跨平臺開發中的優勢與實踐 對于廣大 Web 前端開發者而言&#xff0c;移動端開發似乎總隔著一層“原生”的壁壘。學習 Swift/Kotlin、熟悉 Xcode/Android Studio 的高昂成本&#xff0c;讓許多人望而卻步。然而&#xff0c;“一次編寫&#xff0c;多端運…

QT控件 使用QtServer系統服務實現搭建Aria2下載后臺服務,并使用Http請求訪問Json-RPC接口調用下載退出

前言 最近了解到qt-solutions這個開源項目,仔細研究一番&#xff0c;發現其中的QtServer項目能在Windows系統中創建系統服務&#xff0c;Linux/Unix系統中能作為守護進程使用&#xff0c;之前一直以為編寫服務需要使用Windows api來實現&#xff0c;沒想到這么簡單。 本來之前就…

Python中關于數組的常見操作

Python中關于數組的常見操作 1.創建數組 array []2.添加元素 array.append()3.訪問元素 print(array[2])通過索引進行數組元素的訪問 4.修改元素 array[2] 3直接對想修改的元素位置進行賦值 5.刪除元素 array.remove(2) #刪除元素2del array[2] #刪除索引為2的元素6…