二级缓存使用问题 返回

偶尔会报错:SetKeyValue error , entity & uniqueCode already exist
缓存类都是文档中复制的,现在很奇怪的就是本地无法重现,但是服务器上,爆出来的日志,异常都是使用了WithCache()的查询方法,在去掉方法WithCache()后,无异常抛出
热忱回答(8)
-
fate sta VIP0
2022/12/5SugarCache怎么实现的,这个是Redis类出错
0 回复 -
桥啊桥哥哥 VIP0
2022/12/5public class SugarCache : ICacheService { MemoryCacheHelper cache = new MemoryCacheHelper(); public void Add<V>(string key, V value) { cache.Set(key, value); } public void Add<V>(string key, V value, int cacheDurationInSeconds) { cache.Set(key, value, cacheDurationInSeconds); } public bool ContainsKey<V>(string key) { return cache.Exists(key); } public V Get<V>(string key) { return cache.Get<V>(key); } public IEnumerable<string> GetAllKey<V>() { return cache.GetCacheKeys(); } public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = int.MaxValue) { if (cache.Exists(cacheKey)) { return cache.Get<V>(cacheKey); } else { var result = create(); cache.Set(cacheKey, result, cacheDurationInSeconds); return result; } } public void Remove<V>(string key) { cache.Remove(key); } } public class MemoryCacheHelper { private static readonly MemoryCache Cache = new MemoryCache(new MemoryCacheOptions()); /// <summary> /// 验证缓存项是否存在 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public bool Exists(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); return Cache.TryGetValue(key, out _); } /// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <param name="expiressAbsoulte">绝对过期时长</param> /// <returns></returns> public bool Set(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) { if (key == null) throw new ArgumentNullException(nameof(key)); if (value == null) throw new ArgumentNullException(nameof(value)); Cache.Set(key, value, new MemoryCacheEntryOptions().SetSlidingExpiration(expiresSliding) .SetAbsoluteExpiration(expiressAbsoulte)); return Exists(key); } /// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresIn">缓存时长</param> /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <returns></returns> public bool Set(string key, object value, TimeSpan expiresIn, bool isSliding = false) { if (key == null) throw new ArgumentNullException(nameof(key)); if (value == null) throw new ArgumentNullException(nameof(value)); Cache.Set(key, value, isSliding ? new MemoryCacheEntryOptions().SetSlidingExpiration(expiresIn) : new MemoryCacheEntryOptions().SetAbsoluteExpiration(expiresIn)); return Exists(key); } /// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <returns></returns> public void Set(string key, object value) { Set(key, value, TimeSpan.FromDays(1)); } /// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="ts"></param> /// <returns></returns> public void Set(string key, object value, TimeSpan ts) { Set(key, value, ts, false); } /// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="ts"></param> /// <returns></returns> public void Set(string key, object value, int seconds) { var ts = TimeSpan.FromSeconds(seconds); Set(key, value, ts, false); } #region 删除缓存 /// <summary> /// 删除缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public void Remove(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); Cache.Remove(key); } /// <summary> /// 批量删除缓存 /// </summary> /// <returns></returns> public void RemoveAll(IEnumerable<string> keys) { if (keys == null) throw new ArgumentNullException(nameof(keys)); keys.ToList().ForEach(item => Cache.Remove(item)); } #endregion #region 获取缓存 /// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public T Get<T>(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); return Cache.Get<T>(key); } /// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public object Get(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); return Cache.Get(key); } /// <summary> /// 获取缓存集合 /// </summary> /// <param name="keys">缓存Key集合</param> /// <returns></returns> public IDictionary<string, object> GetAll(IEnumerable<string> keys) { if (keys == null) throw new ArgumentNullException(nameof(keys)); var dict = new Dictionary<string, object>(); keys.ToList().ForEach(item => dict.Add(item, Cache.Get(item))); return dict; } #endregion /// <summary> /// 删除所有缓存 /// </summary> public void RemoveCacheAll() { var l = GetCacheKeys(); foreach (var s in l) { Remove(s); } } /// <summary> /// 删除匹配到的缓存 /// </summary> /// <param name="pattern"></param> /// <returns></returns> public void RemoveCacheRegex(string pattern) { IList<string> l = SearchCacheRegex(pattern); foreach (var s in l) { Remove(s); } } /// <summary> /// 搜索 匹配到的缓存 /// </summary> /// <param name="pattern"></param> /// <returns></returns> public IList<string> SearchCacheRegex(string pattern) { var cacheKeys = GetCacheKeys(); var l = cacheKeys.Where(k => Regex.IsMatch(k, pattern)).ToList(); return l.AsReadOnly(); } /// <summary> /// 获取所有缓存键 /// </summary> /// <returns></returns> public List<string> GetCacheKeys() { const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; var entries = Cache.GetType().GetField("_entries", flags).GetValue(Cache); var cacheItems = entries as IDictionary; var keys = new List<string>(); if (cacheItems == null) return keys; foreach (DictionaryEntry cacheItem in cacheItems) { keys.Add(cacheItem.Key.ToString()); } return keys; } }
0 回复 -
fate sta VIP0
2022/12/5这个自个调试一下吧 别人提供的未必没有BUG
0 回复 -
桥啊桥哥哥 VIP0
2022/12/5@fate sta:我后面调试过的,首先把所有的处理使用try包裹,还是存在异常。
然后我根据日志的路径,找到下面这个方法
public void SetTable<T>(Expression<Func<T, object>> keyExpression, Expression<Func<T, object>> valueTextExpression, string uniqueCode = null, Expression<Func<T, object>> whereExpression=null) { lock (SqlFuncExtendsion.TableInfos) { var entity = this.Context.EntityMaintenance.GetEntityInfo<T>(); ExpressionContext context = new ExpressionContext(); var query = Context.Queryable<T>().QueryBuilder; var keyValue = query.GetExpressionValue(keyExpression, ResolveExpressType.FieldSingle).GetString(); var ValueValue = query.GetExpressionValue(valueTextExpression, ResolveExpressType.FieldSingle).GetString(); string where = null; if (whereExpression != null) { where = query.GetExpressionValue(whereExpression, ResolveExpressType.WhereSingle).GetResultString(); } context.MappingTables = this.Context.MappingTables; if (!SqlFuncExtendsion.TableInfos.Any(y => y.Type == typeof(T) && y.Code == uniqueCode)) { SqlFuncExtendsion.TableInfos.Add(new ConfigTableInfo() { Type = typeof(T), TableName = entity.DbTableName, Key = keyValue, Value = ValueValue, Where = where, Parameter = query.Parameters, Code = uniqueCode }); } else { Check.Exception(true, "SetKeyValue error , entity & uniqueCode already exist"); } } }
日志大致如下:
SqlSugar.SqlSugarException: SetKeyValue error , entity & uniqueCode already exist at SqlSugar.Check.Exception(Boolean isException, String message, String[] args) at SqlSugar.ConfigQuery.SetTable[T](Expression`1 keyExpression, Expression`1 valueTextExpression, String uniqueCode, Expression`1 whereExpression) at SqlSugar.ConfigQuery.SetTable[T](Expression`1 key, Expression`1 value) at SqlSugar.SqlSugarScope.GetAsyncContext(String key) at SqlSugar.SqlSugarScope.GetContext() at SqlSugar.SqlSugarScope.get_ScopedContext() at SqlSugar.SqlSugarScope.Queryable[T]()
找到异常抛出的地方:Check.Exception(true, "SetKeyValue error , entity & uniqueCode already exist");
对此感到比较疑惑,为什么会抛出这个异常?
0 回复 -
桥啊桥哥哥 VIP0
2022/12/6@桥啊桥哥哥:补充:后续调试中发现,有一个未调用二级缓存的接口也出现该异常,后面取消所有的二级缓存,配置,使用等,还是出现了
背景:.net 6,iis 10,托管在iis,每次重新启动或者停止、启动后,瞬间接受三四个请求,就出现了此异常
0 回复 -
桥啊桥哥哥 VIP0
2022/12/6@桥啊桥哥哥:由于定位到了启动后第一次批量请求的异常率较高,检查代码后发现下方代码,包上try...catch后查看日志
//配置EntArea if (!db.ConfigQuery.Any()) //保证只配置一次不能更新,该配置是全局静态存储 { try { db.ConfigQuery.SetTable<EntArea>(it => it.Code, it => it.Name); } catch (Exception ex) { log.LogError("配置EntArea异常", ex); } //多个配置可以一起写在下面 }
根据日志,完全可以定位问题发生在这里,调用SetTable引发的异常
还是很迷惑,此用法是根据文档:https://www.donet5.com/Home/Doc?typeId=2309,1.3 使用配置查询,的使用方法,竟然会抛出异常
0 回复 -
桥啊桥哥哥 VIP0
2022/12/6@fate sta:所以问题好像并不是缓存的问题,而是这个静态的配置
0 回复 -
fate sta VIP0
2022/12/6@桥啊桥哥哥:这个保证只配置一次就行了
0 回复