导读:
◆缘起
◆缓存简述
◆缓存依赖简述
◆自定义缓存依赖分析
◆数据库缓存依赖学习
◆LINQ缓存依赖实现
◆文档更新说明
◆附:缓存依赖研究项目源码(包括数据库)
◆参考资料
一、缘起
(本文发布于博客园,作者在博客园的博客地址是:http://www.cnblogs.com/xpnew/ 原文地址: http://www.cnblogs.com/xpnew/archive/2012/05/03/LinQCacheDependency.html ,由于转载会造成图片、格式丢失,以及不能获得文档的最后更新,所以在此特别声明)
最近做的一个客户项目,客户提出的要求是参数可定制,例如会员积分达到3000可以升一档。
实现这个需求,其实很容易,只要把相关的参数都写到数据库或者xml文件当中,使用的时候再读出然后作比较就可以了。
从性能优化的角度来讲,当然不能是每次使用的时候都重新读取一遍。
在asp时代,优化性能的一个关键就是把数据保存到Application和Session当中,到了asp.net时代,就提供了一个“更好”的工具:Cache。
以前就研究过Cache,不过因为需要优化的数据较少,所以仍然使用Application。
做到这个项目,虽然需要缓存的数据不多,但是因为通过缓存依赖可以“及时”获得更新,所以决定下大力气仔细研究一下。
我现在做东西使用的是LINQ,并且分成DALEntery、DAL、BLL、WEB这4层,所以不能直接使用数据库缓存依赖,于是在网站找了好久,都没有找到在LINQ当中使用缓存依赖的技术资料,最后没办法,只好研究其它的缓存依赖方式。
写出这篇笔记之前,我的学习路线是:先看MSDN当中Asp.net当中使用缓存的部分,然后一些关于“自定义缓存”方面的技术博客,最后是“数据库缓存依赖”的技术资料并且动手做了一些实验,然后是总结分析。
二、缓存简述
缓存的使用方法,就是用Add或者Insert方法,把对象存储到缓存当中。
缓存的技术需要研究超时、页面缓存、缓存依赖等细节。
三、缓存依赖简述
缓存依赖就是在正常的缓存到期之前,提前获知原始数据已经更改,以最快的速度保持数据的同步。
缓存依赖有几种形式:
四、自定义缓存依赖分析
从网站看到了一堆资料之后,可以总结出以下几点:
1、派生于CacheDependency
2、通过计时器来轮询
3、需要自己实现比较和判定,以确定缓存是否已经更新/修改
五、数据库缓存依赖学习
《系统缓存全解析6:数据库缓存依赖》阅读了两遍之后,我自己动手做了一下实验,实验的结果和文章描述的完全一致。
为了进一步的理解,我又在数据库里创建了“新闻”、“案例”两个表,作为对比对象。
其中新闻使用了缓存,超时设置为15分钟,案例没有缓存。
实验是在两个页面时行的,一个是list,一个是Insert。前者用GrideView控件显示产品、新闻、案例的列表,后者用DetailsView控件插入数据。
实验的现象一:
2、新添加的新闻,不会立刻显示在列表页上,直到15分钟之后才出现。
初步结论:使用缓存依赖,能够保持数据的同步。
实验的现象二:
新添加了产品,立即在列表页面刷新,列表页面有时候不能立即显示。
进一步结论:
缓存依赖,是“理论”上的即时同步,并非真的分秒不差。究其根源,应该是因为缓存依赖,其实是基于轮询的方式实现的。
然后打开数据库,研究了一下,数据库缓存依赖的原理终于真像大白了:
1、首先是在数据库创建了一系列的存储过程
2、然后是在数据库创建了一个表:AspNet_sqlCacheTablesForChangeNotification
3、在需要监视的表上创建触发器:[P_Product_AspNet_sqlCacheNotification_Trigger]
4、每次被监视的表上修改之后,都要通过触发器=》存储过程=》来修改表AspNet_sqlCacheTablesForChangeNotification相应的记录。
5、Asp.net通过web.config的设置,轮询数据库里的表AspNet_sqlCacheTablesForChangeNotification
6、根据在Cache当中指定了的缓存依赖,比较表名(AspNet_sqlCacheTablesForChangeNotification的[tableName]字段)对应的changeId是否发生变化,判断缓存源数据是否发生变化,然后决定缓存项提前过期。
六、LINQ缓存依赖实现
1、基础工作:
创建表的触发器,准备表修改记录表,以及二者之间的存储过程。
当然,这些可以直接使用Asp.net提供的这些功能。
2、在DAL层写一个类“DBCacheDependencyDAL.cs”,实现查询[表修改记录表]的功能。
3、在BLL层写一个类“LinQCacheDependencyServer.cs”实现自定义缓存依赖,这个类派生于CacheDependency,并且实现以下的细节:
TableName字段,保存要监视的表名
CurrentId字段,保存缓存创建时changeId字段的值,因为缓存失效时,会重新创建,所以这个属性为只读属性。
DBCallBack(object sender)委托,这个委托会被传递给计时器调用,被调用的时候,它调用CheckTableChanged方法检查表是否已经更新,如果已经更新,那么就会调用基类的NotifyDependencyChanged方法,通知依赖项已经更改。
CheckTableChanged方法:比较CurrentId字段和数据库里的changeId字段,不同则表示已经更新。
4、在添加缓存的时候添加LinQCacheDependency类的实例,作为缓存依赖。
◆文档更新说明:
2012年5月3日 17:00
◆参数资料:
《《解剖PetShop》系列之四 PetShop之ASP.NET缓存》
http://www.cnblogs.com/wayfarer/archive/2006/11/01/547060.html
《系统缓存全解析6:数据库缓存依赖》
http://www.cnblogs.com/ltp/archive/2009/06/30/1514331.html
《ASP.NET 3.5核心编程学习笔记(38):自定义缓存依赖》
http://www.cnblogs.com/free722/archive/2011/04/25/2028780.html
《asp.net 2.0 中使用自定义缓存依赖》
http://www.cnblogs.com/sunwaywei/archive/2006/06/11/423312.html
《linq to sql中的自动缓存(对象跟踪)》
http://www.mysjtu.com/page/M0/S438/438073.html
《缓存依赖》
http://hi.baidu.com/reallycan/blog/item/89cb5adff9d60c4f95ee3774.html