You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用MARS的ASP.NET Web API缓存强制重置方案问询

数据库修改后数据不更新的缓存问题分析与解决方案

首先,咱们先把核心问题拆解清楚:你遇到的是数据库数据修改后前端无法显示最新内容,排查后排除了WCF服务缓存的问题,但发现两个关键点:Entity Framework启用了MARS(Multiple Active Result Sets),同时代码里还有基于用户Session的自定义缓存CardRegistrationPartyCache。这两个都是导致旧数据残留的潜在原因,咱们一个个来解决。

一、核心问题定位

1. 自定义Session缓存是首要嫌疑

看你的CardRegistrationPartyService代码:缓存逻辑是先从Session里取数据,只有缓存不存在时才会调用数据库接口加载并更新缓存。但问题在于——当数据库里的数据被修改后,这个缓存并没有被同步更新!所以前端拿到的始终是Session里的旧数据,这大概率是最直接的原因。

2. MARS会话缓存的影响

启用MARS后,SqlClient会在连接内缓存MARS逻辑会话来降低开销,但这确实可能导致旧的查询结果被复用。不过禁用MARS需要修改多个服务的连接字符串,成本太高,咱们先优先解决自定义缓存的问题,再处理MARS的潜在影响。

二、针对性解决方案

方案1:修改操作同步更新自定义缓存(最直接有效)

既然缓存是存在用户Session里的,那在执行数据修改(更新/删除)的方法里,主动同步更新或移除对应缓存项即可:

示例:更新数据时同步缓存

public void UpdateCardRegistrationParty(CardRegistrationParty updatedCrp)
{
    // 第一步:先执行数据库更新操作
    Infrastructure.CreateTestsOfEriService().UpdateCardRegistrationParty(updatedCrp);
    
    // 第二步:同步更新Session缓存
    var cache = new CardRegistrationPartyCache(Infrastructure.CreateUserSessionService());
    cache.AddOrUpdate(updatedCrp);
}

示例:删除数据时移除缓存

public void DeleteCardRegistrationParty(int barcodeID)
{
    // 第一步:执行数据库删除
    Infrastructure.CreateTestsOfEriService().DeleteCardRegistrationParty(barcodeID);
    
    // 第二步:移除对应缓存键
    var cache = new CardRegistrationPartyCache(Infrastructure.CreateUserSessionService());
    string cacheKey = cache.GetType().FullName + barcodeID.ToString();
    Infrastructure.CreateUserSessionService().RemoveUserData(cacheKey);
}

方案2:前端层面主动清除缓存(AngularJS端处理)

如果后端修改缓存的成本较高,可以在前端操作完成后,主动清除对应的数据缓存:

示例:AngularJS服务中清除缓存

app.factory('cardRegistrationService', function($http, $cacheFactory) {
    // 创建专属缓存
    var cardCache = $cacheFactory('cardRegistrationCache');
    
    return {
        // 获取数据时使用缓存
        getPartyList: function(barcodeIds) {
            var url = `/api/cardparties?barcodes=${barcodeIds.join(',')}`;
            return $http.get(url, { cache: cardCache });
        },
        // 更新数据后清除缓存
        updateParty: function(updatedParty) {
            return $http.put('/api/cardparties', updatedParty)
                .then(function(response) {
                    // 清除对应缓存键,下次请求会重新拉取最新数据
                    cardCache.remove(`/api/cardparties?barcodes=${updatedParty.BarcodeID}`);
                    return response;
                });
        }
    };
});

方案3:优化EF层面的缓存(解决MARS潜在影响)

如果MARS导致数据库连接层面的旧数据残留,可以通过以下方式优化:

  1. 禁用EF的跟踪缓存:在查询时添加AsNoTracking(),避免DbContext缓存旧数据
// 在获取DTO的方法中修改查询逻辑
public IEnumerable<CardRegistrationPartyDTO> GetCardRegistrationPartyListWithChecks(int[] barcodeIDs)
{
    using(var dbContext = new YourDbContext())
    {
        return dbContext.CardRegistrationParties
            .AsNoTracking() // 禁用EF的一级缓存
            .Where(crp => barcodeIDs.Contains(crp.BarcodeID))
            .ToList();
    }
}
  1. 确保每次操作使用新的DbContext:避免复用同一个DbContext导致旧数据残留,比如在Infrastructure.CreateTestsOfEriService()中每次都创建新的上下文实例。

方案4:给缓存添加过期策略(长期优化)

给自定义Session缓存加上过期时间,即使忘记同步更新,缓存过期后也会自动从数据库重新加载:

示例:扩展Session缓存的过期逻辑

// 先定义带过期时间的缓存项类
public class CachedItem<T>
{
    public T Value { get; set; }
    public DateTime ExpiresAt { get; set; }
}

// 扩展UserSessionService的方法
public void SetUserDataWithExpiry(string key, object value, TimeSpan expiry)
{
    HttpContext.Current.Session[key] = new CachedItem<object>
    {
        Value = value,
        ExpiresAt = DateTime.Now.Add(expiry)
    };
}

public T UserData<T>(string key)
{
    var cachedItem = HttpContext.Current.Session[key] as CachedItem<object>;
    if(cachedItem == null || cachedItem.ExpiresAt < DateTime.Now)
    {
        // 缓存过期或不存在,移除并返回默认值
        HttpContext.Current.Session.Remove(key);
        return default(T);
    }
    return (T)cachedItem.Value;
}

然后修改CardRegistrationPartyCache的AddOrUpdate方法,设置比如10分钟的过期时间:

public void AddOrUpdate(CardRegistrationParty crp)
{
    string key = this.GetType().FullName + crp.BarcodeID.ToString();
    _userSessionService.SetUserDataWithExpiry(key, crp, TimeSpan.FromMinutes(10));
}

三、验证步骤

  1. 先验证自定义缓存是否是根源:修改数据后,手动清除当前用户的Session(比如重启服务或调用缓存移除方法),看前端是否显示最新数据。
  2. 如果是,优先实施方案1,确保修改操作同步更新缓存。
  3. 再测试EF层面的优化,添加AsNoTracking()后观察数据是否正常更新。
  4. 最后根据需求考虑前端缓存清理或过期策略的长期优化。

内容的提问来源于stack exchange,提问作者Tibomso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:55:56