首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.Net cache与cache更新

.Net cache与cache更新

作者头像
FlyLolo
发布2018-05-17 15:33:57
9550
发布2018-05-17 15:33:57
举报
文章被收录于专栏:Core NetCore Net

主要用到 System.Runtime.Caching

框架自动给了一个默认值 MemoryCache.Default;

查看微软关于MemoryCache的介绍,可以看到它有Add、Get、Set 、 Contains 、Remove等几个方法, 也就是我们常用的了,比较简单

网上找了一段对这个封装的代码:

/// <summary>
    /// Represents a MemoryCacheCache
    /// </summary>
    public static class CacheManager
    {
        public static ObjectCache Cache
        {
            get
            {
                return MemoryCache.Default;
            }
        }

        public static bool Contains(string key)
        {
            return Cache.Contains(key);
        }

        /// <summary>
        /// Gets or sets the value associated with the specified key.
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="key">The key of the value to get.</param>
        /// <returns>The value associated with the specified key.</returns>
        public static T Get<T>(string key)
        {
            return (T)Cache[key];
        }

        /// <summary>
        /// Adds the specified key and object to the cache.
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="data">Data</param>
        /// <param name="cacheTime">Cache time</param>
        public static void Set(string key, object data, int cacheTime)
        {
            if (data == null)
                return;

            var policy = new CacheItemPolicy();
            policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);
            Cache.Set(new CacheItem(key, data), policy);
        }/// <summary>
        /// Gets a value indicating whether the value associated with the specified key is cached
        /// </summary>
        /// <param name="key">key</param>
        /// <returns>Result</returns>
        public static bool IsSet(string key)
        {
            return (Cache.Contains(key));
        }

        /// <summary>
        /// Removes the value with the specified key from the cache
        /// </summary>
        /// <param name="key">/key</param>
        public static void Remove(string key)
        {
            Cache.Remove(key);
        }

        /// <summary>
        /// Removes items by pattern
        /// </summary>
        /// <param name="pattern">pattern</param>
        public static void RemoveByPattern(string pattern)
        {
            var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
            var keysToRemove = new List<String>();

            foreach (var item in Cache)
                if (regex.IsMatch(item.Key))
                    keysToRemove.Add(item.Key);

            foreach (string key in keysToRemove)
            {
                Remove(key);
            }
        }

        /// <summary>
        /// Clear all cache data
        /// </summary>
        public static void Clear()
        {
            foreach (var item in Cache)
                Remove(item.Key);
        }

框架提供了缓存的更新机制

查看MemoryCache的Add方法:Add(CacheItem, CacheItemPolicy)

其中的参数CacheItemPolicy有一个ChangeMonitors属性, 该属性可选项为

System.Runtime.Caching.CacheEntryChangeMonitor System.Runtime.Caching.FileChangeMonitor System.Runtime.Caching.SqlChangeMonitor

可以看出添加cache的时候可以设置此cache的几种类型的依赖

网上看到有FileChangeMonitor的例子, 现在小罗遇到的需求是需要根据系统表来更新缓存,

即数据库中的数据发生了改变, 此时更新本次添加的缓存

对上面的代码添加方法

        public static void SetWithSql(string key, object data, string connStr, string sql, CacheEntryRemovedCallback callback)
        {
            if (data == null)
                return;

            Cache.Add(new CacheItem(key, data), SqlChangePolicy(connStr, sql, callback));
        }

 private static CacheItemPolicy SqlChangePolicy(string connStr,string sql, CacheEntryRemovedCallback callback)
        {
            SqlDependency.Start(connStr);
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                using (SqlCommand command = new SqlCommand(sql, conn))
                {
                    command.Notification = null;
                    conn.Open();

                    SqlDependency dependency = new SqlDependency(command);
                    dependency.AddCommandDependency(command);

                    SqlChangeMonitor monitor = new SqlChangeMonitor(dependency);

                    CacheItemPolicy policy = new CacheItemPolicy();
                    policy.ChangeMonitors.Add(monitor);

                    command.ExecuteScalar();
                    policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(60*24);
                    policy.RemovedCallback = callback;
                    return policy;
                }
            }
        }

添加cache项的时候, 传入SqlConnection和相应的sql, 目的是当sql对应的查询结果发生变化的时候, 清除此项缓存

注意是清除, 可以看到改方法有一个CacheEntryRemovedCallback参数,当此项被清除后会调用该callback方法

如果想"更新", 现在看到这个callback方法应该知道怎么做了

看着微软的帮助一步一步做下来简单, 但出了一个问题,就是刚Add进去, 马上CacheEntryRemovedCallback方法就被调用了, 数据改变了? 确认一下没有,

继续研究帮助,

看一下SqlChangeMonitor的构造函数, 参数是SqlDependency

SqlDependency是System.Data.SqlClient 命名空间中的,

微软这样说:SqlDependency 对象都表示应用程序和 SQL Server 实例之间的查询通知依赖项。 应用程序可以创建 SqlDependency 对象并进行注册以接收通知通过 OnChangeEventHandler 事件处理程序。

原来此对象是数据库中做监视和通知用的, 被"征用"过来的.

这就好办了, 根据帮助文档, 发现这个sql的要求真不是一般的严格

现在说一下这个"sql", 这个sql首先要求是一个select语句,然后:

  • 必须显式说明 SELECT 语句中提取的列,并且表名必须限定为两部分组成的名称。注意,这意味着语句中引用的所有表都必须处于同一数据库中。
  • 语句不能使用星号 (*) 或 table_name.* 语法指定列。
  • 语句不能使用未命名列或重复的列名。
  • 语句必须引用基表。
  • 语句不能引用具有计算列的表。
  • 在 SELECT 语句中提取的列不能包含聚合表达式,除非语句使用 GROUP BY 表达式。提供 GROUP BY 表达式时,选择列表便可以包含聚合函数 COUNT_BIG() 或 SUM()。但是,不能为可为空的列指定 SUM()。语句不能指定 HAVING、CUBE 或 ROLLUP。
  • 在用作简单表达式的 SELECT 语句中提取的列不能多次显示。
  • 语句不能包含 PIVOT 或 UNPIVOT 运算符。
  • 语句不能包含 UNION、INTERSECT 或 EXCEPT 运算符。
  • 语句不能引用视图。
  • 语句不能包含下列任意一个:DISTINCT、COMPUTE、COMPUTE BY 或 INTO。
  • 语句不能引用服务器全局变量 (@@variable_name)。
  • 语句不能引用派生表、临时表或表变量。
  • 语句不能从其他数据库或服务器中引用表或视图。
  • 语句不能包含子查询、外部联接或自联接。
  • 语句不能引用下列大型对象类型:text、ntext 和 image。
  • 语句不能使用 CONTAINS 或 FREETEXT 全文谓词。
  • 语句不能使用行集函数,包括 OPENROWSET 和 OPENQUERY。
  • 语句不能使用下列任何一个聚合函数:AVG、COUNT(*)、MAX、MIN、STDEV、STDEVP、VAR 或 VARP。
  • 语句不能使用任何具有不确定性的函数,包括排名函数和开窗函数。
  • 语句不能包含用户定义聚合。
  • 语句不能引用系统表或视图,包括目录视图和动态管理视图。
  • 语句不能包含 FOR BROWSE 信息。
  • 语句不能引用队列。
  • 语句不能包含无法更改和无法返回结果的条件语句(如 WHERE 1=0)。
  • 语句不能指定 READPAST 锁提示。
  • 语句不能引用任何 Service Broker QUEUE。
  • 语句不能引用同义词。
  • 语句不能具有基于 double/real 数据类型的比较或表达式。
  • 语句不得使用 TOP 表达式。

多吧, 还有个问题,就是要启用数据库的BROKER 

ALTER DATABASE database_name SET TRUSTWORTHY ON WITH ROLLBACK IMMEDIATE ALTER DATABASE database_name SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE ALTER AUTHORIZATION ON DATABASE::database_name TO sa

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-11-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档