ASP.NET MVC 首页节假日校验频繁查询数据库优化咨询
ASP.NET MVC 节假日判断缓存优化方案
方案选择说明
节假日判断是全局公共规则,和单个用户无关,不建议使用Session实现:Session属于用户会话级存储,会导致每个用户都单独存储一份判断结果,额外占用资源,性价比极低,优先选择全局缓存方案。
方案1:单服务器部署用内置内存缓存(最常用)
- 第一步:注册缓存服务
在Program.cs(.NET 6+)或者Startup.cs的ConfigureServices方法中添加服务注册:
// .NET 6+ Program.cs示例 builder.Services.AddMemoryCache();
- 第二步:在控制器中注入缓存服务
修改CustomersController的构造函数,注入IMemoryCache实例:
private readonly YourDbContext _context; private readonly IMemoryCache _memoryCache; public CustomersController(YourDbContext context, IMemoryCache memoryCache) { _context = context; _memoryCache = memoryCache; }
- 第三步:修改Index方法的判断逻辑
替换原有数据库查询逻辑,优先走缓存,缓存失效后才查数据库,缓存过期时间设置为美东时间当日午夜,自动更新次日的判断结果:
public async Task<IActionResult> Index(string sortOrder, string searchString, int? pageNumber, string currentFilter) { var timeUtc = DateTime.UtcNow; var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); var todayDt = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, easternZone); // 按美东时间日期生成缓存key,确保每天的结果单独缓存 var cacheKey = $"IsHoliday_{todayDt:yyyyMMdd}"; // 缓存中不存在数据时才查询数据库 if (!_memoryCache.TryGetValue(cacheKey, out bool isHoliday)) { // 用Any替代Count,只要判断存在即可,数据库查询效率更高 isHoliday = _context.HolidayWeeks.Any(hc => hc.HolidateDate.Date == todayDt.Date); // 设置缓存过期时间为美东时间当日午夜,到期自动失效 var expireTime = new DateTimeOffset(todayDt.Date.AddDays(1), easternZone.BaseUtcOffset); _memoryCache.Set(cacheKey, isHoliday, expireTime); } if (isHoliday) { return View("/Views/Customers/AppNotAvailable.cshtml"); } // 原有客户页面业务逻辑 // ... }
方案2:多服务器分布式部署用分布式缓存
如果你的应用是多实例部署,为了避免每个实例都单独查询数据库,可以使用ASP.NET Core提供的IDistributedCache分布式缓存,底层可以对接Redis、SQL Server等公共存储,逻辑和内存缓存基本一致,只是接口调用方式略有差异,缓存数据全局共享,所有实例共用同一份判断结果。
进阶优化:全局拦截统一处理
如果后续有多个页面都需要做节假日拦截,建议把判断逻辑封装为Action过滤器或者中间件,不用在每个Action中重复编写代码:
- 自定义节假日校验过滤器:
public class HolidayCheckFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { var cache = context.HttpContext.RequestServices.GetRequiredService<IMemoryCache>(); var dbContext = context.HttpContext.RequestServices.GetRequiredService<YourDbContext>(); // 复用上述节假日判断逻辑 var timeUtc = DateTime.UtcNow; var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); var todayDt = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, easternZone); var cacheKey = $"IsHoliday_{todayDt:yyyyMMdd}"; if (!cache.TryGetValue(cacheKey, out bool isHoliday)) { isHoliday = dbContext.HolidayWeeks.Any(hc => hc.HolidateDate.Date == todayDt.Date); var expireTime = new DateTimeOffset(todayDt.Date.AddDays(1), easternZone.BaseUtcOffset); cache.Set(cacheKey, isHoliday, expireTime); } if (isHoliday) { context.Result = new ViewResult { ViewName = "/Views/Customers/AppNotAvailable.cshtml" }; } } public void OnActionExecuted(ActionExecutedContext context) { // 无需实现 } }
- 注册过滤器,可以选择全局注册对所有请求生效,或者只给需要拦截的Controller/Action打标记使用。
内容的提问来源于stack exchange,提问作者user4912134
相关产品推荐
相关产品推荐

