在AS P.N ET 2.0中操作数据之五十八在程序启动阶段缓存数据
作者 h e ke r2007字体 [增加减小]类型转载时间 2016-05-17我要评论
前面我们分别介绍了在ObjectDataSource缓存数据和在分层架构中缓存数据本文介绍ASP.NET 2.0中在程序启动阶段在Globa l.asax文件中缓存数据。
导言
前面2章考察了在表现层和缓存层缓存数据。在第56章我们探讨了在表现层设置ObjectDataSource的相关cache属性来缓存数据。在第57章我们探讨了创建一个单独的分开的缓存层。这2章都是采用―应激装载‖ reactive loading的模式来缓存数据。该模式下每次请求数据时系统先检查其是否在内存如果没有则从数据源——比如数据库来获取数据然后将其存储在内存里。该模式的优势在于执行起来很容易而缺点之一在于应―请求‖ req uests而执行。试想一下在前面章节我们通过缓存层来展示产品信息当第一次登录该页面或缓存数据因为缓存时间结束等原因从内存清除以后再次访问该页面时因为数据没有储存在内存里请求只能从数据库获取数据。这样一来花的时间就比直接从内存获取数据要长一些。
―预装载‖(Proactive loading)可以使用2种模式来预装载数据。第一种模式 Proactiveload ing使用一些方法( process)来判断源数据(underlying data)是否发生改变并及时对缓存数据进行更新——比如周期性的检查源数据或者当源数据发生改变时立即通知更新。不过该模式的弊端在于执行起来比较困难你必须创建、管理、执行一个具体的方法来检查源数据的更改情况 以更新缓存数据。
另一个模式同时也是本文要探讨的内容就是在程序启动时便装载数据入内存。该模式对缓存静态数据(static data)尤其有用 比如查找数据库表里的记录。
注意关于―应激装载‖(reactive loading)和―预装载‖(proactive loading)的区别请参考文章《 Caching Architecture Guide for .NET Framework Appl ications》的《Managing the Contents of a Cache》章节 (http://msdn2.microsoft.com/en-us/l ibrary/ms.aspx)第一步在程序启动阶段决定缓存哪些数据
我们在前面2章探讨的reactive loading模式的示例适合处理这些数据周期性地改变且生成(generate)数据不需要太长的时间。但是如果缓存的数据从未改变那么reactiveload ing模式使用的周期(ex p iry)就显的有点多余。另外如果需要缓存的数据要花很长的时间才能生产 当用户请求发现内存为空时用户将等很长的时间来检索并返回数据。对此可以考虑将静态数据和需要很长时间才能生成的数据在程序启动阶段就缓存。
虽然数据库有很多动态的经常改变的值不过静态值也不少。举例数据库表Patients有一个PrimaryLanguage列其值可以为English, Span ish, French, Russian, Japanese等。不过我们不会直接在表Patients里存储―Engl ish‖或―French‖等字符串而是在供查找的表Languages里存储。如图1 John Doe的primary language是Engl ish而Ed Johnson的是Russian.
图1表Languages为表Patients所使用的查找表
在编辑或创建新patient的用户界面里将包含一个下拉列表框列出表Languages里的所有语言项。不缓存的话每次登录该界面系统都会查询表Languages这样显地和浪费也没有必要。因为表Languages不会频繁的改变。
我们可以用前面探讨的reactive load ing模式来对数据Languages进行缓存。不过 reactive loading模式会使用基于时间的缓存周期(time-based expiry),这对静态数据来说没有必要。最好的办法是在程序启动阶段进行预装载。
在本文我们将探讨如何缓存―查找表‖(lookup table,例如Languages表对Patients表来说就是查找表)数据和其它的静态信息。
第二步考察缓存数据的不同途径
在一个AS P.N ET应用程序里我们可以使用多种方法来缓存信息。在前面的教程我们看到的是data cache其实通过使用static members(静态成员)或appl ication state(应用程序状态)我们也可以将对象(o bjects)缓存。
当处理一个类时我们在访问其成员(members)前应先实例化。比如为了调用BLL层里的一个方法我们首先要创建该类的实例
?
在调用SomeMethod或处理SomeProperty之前我们必须首先用关键字new来创建一个类的实例。 SomeMethod和SomeProperty要与一个具体的实例对应起来这些成员的生命周期(l ifetime)取决与对应对象的生命周期。另一方面 Static members 比如变量、属性、方法等对该类的所有实例来说都是共享的因此其生命周期与该类的生命周期一样长。 Static members要用关键字static来标识。
除了static members外还可以使用appl ication state。每一个ASP.NET应用程序都包含一个name/value集它对应用程序的所有页面和用户都是共享的。可以通过HttpContext class类的Appl icat ion property属性来访问它。在页面的后台代码我们可以这样访问它
?
data cache提供了丰富的缓存数据的API(应用程序接口)基于时间和从属体的缓存周期(time- and dependency-based expiries)的机制以及cache item priorities等。在本文我们将看到3种缓存静态数据的技术。
第三步缓存Suppliers Table表的数据
我们用到的Northwind数据库并没有―查找表‖(lookup tables),DAL层用到的4个表的值也并非静态的。没必要花时间来向DAL层添加一个新数据库表再在B LL层添加新的类和新的方法我们在本教程假定表Su p p lie rs的数据是静态的 因此我们在程序启动是缓存其数据。
首先我们在CL文件夹里创建一个名为StaticCache.cs的新类。
图2:在CL文件夹里创建StaticCache.cs类
我们需要添加一个在程序启动时装载数据的方法 同样还有一个从内存返回数据的方法。?
在上述代码里我们在LoadStaticCache()方法里用一个static member变量suppl iers来保存Suppl iersBLL类的GetSuppl iers()方法返回的结果。该LoadStaticCache()方法应该在程序启动阶段就被调用。一旦数据在启动时就被加载到内存任何要用到suppl ier信息的页面都可以调用StaticCache class类的GetSuppl iers()方法。因此访问数据库获取suppl iers信息的情况只会发生一次就是在启动阶段。
除了static member变量外我们还可以使用appl ication state或data cache。下面的代码将类进行修改它使用appl ication state:
?
在LoadStaticCache()方法里 su ppl ier信息是存储在appl icat ion变量key里。在GetSu ppl iers()方法里它作为Northwind.Su ppl iersDataTab le类型返回。 由于我们可以在ASP.NET页面的后台代码里使用Appl ication["key"]来访问appl icat ion state所以在这里我们必须使用HttpCo ntext.C u rrent.Ap p l icatio n["key"]来获取当前的HttpCo ntext。
同样我们可以使用data cache如下所示
?
23
向data cache添加一个条目且没指定时间周期(no time-based expiry)为此我们System.Web.Caching.Cache.NoAbsoluteExpiration和System.Web.Caching.Cache.NoSlid ingExpirat ion值作为输入参数之一。在上面的data cache的Insert()方法里我们指定了缓存条目的优先级(priority).优先级用以指明当内存容量不足时哪些条目应从内存移除。在此我们将优先级设为不可移除(也就是对应的nul l)这就确保了当内存不足时不会将其移除。
注意本文下载代码里的StaticCache class类使用的是static member变量技术关于applicationstate和data cache技术的代码可以在类文件(class fi le)里的注释部分找到。
第四步在程序启动是执行代码
为了在程序启动时执行代码我们需要创建一个名为Globa l.asax的文件。该文件包含了a p p l ic at io n、 se ss io n和req u est级事件的事件处理器。在该文件里我们将添加在程序启动时要执行的代码。
要在网站根目录里添加Globa l.asax文件在Visua l Studio解决资源管理器里右击网站项目选Add New Item从Add New Item对话框里选择Global应用程序项目类型,然后点Add按钮。
注意如果你的根目录里已经存在Global.asax文件 Global应用程序项目类型就不会出现在Add New Item对话框里。
图3在根目录添加Global.asax文件。
默认的Globa l.asax文件里包括了5个方法每个方法都有一个服务器端(server-side)<scr ipt>标记
Ap p l icat io n_Sta rt–当程序启动时执行
Ap p l ic at io n_E n d –当程序完结时执行
Appl icat io n_Error–每当程序发生未经处理(u n hand led)的异常时发生。
Sess io n_Sta rt–当创建一个sessio n时执行
Sess io n_E n d –当sessio n完结时或被移除时发生
Appl icat ion_Start事件处理器在程序的生命周期(l ife cycle)里只发生一次。程序起始于一个AS P.N ET资源(reso u rce)首次被请求持续运行直到程序重新启动为止。关于程序生命周期的更多细节请参阅文章《ASP.NET Appl ication Life Cycle Overview》 http://msdn2.microsoft.com/en-us/l ibrary/ms.aspx
本文我们只需要为Ap p l icat io n_Sta rt方法添加代码放心大胆的将其它方法删除。在Appl icat ion_Start里仅仅调用StaticCacheclass类的LoadStaticCache()方法。这将装载并缓存supplier信息
?
要做的就是这些在程序开始时 LoadStaticCache()方法会从BLL获取suppl ier信息再存储进一个static member变量(或是你在StaticCache class类里面用的其它一些cachesto re)。为验证起见在Ap p l icatio n_Start方法里设置断点(b reakpo int)并执行程序。另外在并发请求(Su bseq uent req uests)时不会执行Appl icat ion_Start方法。
图4用B reakpoint来验证Applicat ion_Start事件处理器的执行
注意如果你在首次调试时没有遇到Application_Start breakpoint那是因为你的程序已经启动了。可以修改Global.asax或Web.config文件来强迫程序重新启动。你仅仅在这些文件的末尾添加(或删除)一个空白行来快速的重启程序。
第五步展示缓存数据
现在 StaticCache class类在程序启动时将suppl ier相关的数据进行了缓存。要在表现层使用这些数据我们可以在ASP.NET页面的后台代码通过ObjectDataSou rce控件或编程调用StaticCache class类的GetSuppl iers()方法。让我们看看如何使用ObjectDataSource和GridView控件来展示缓存的su ppl ier信息。
首先打开文件夹里的AtAp p l icatio n Sta rtu p.aspx页面在―设计‖模式里从工具箱里拖一个GridView控件到页面设置其ID为Su ppliers。然后从其智能标签里选择创建一个新的ObjectDataSource名为Suppl iersCachedDataSource设置它使用StaticCache class类的GetSuppliers()方法。
提速啦的来历提速啦是 网站 本着“良心 便宜 稳定”的初衷 为小白用户避免被坑 由赣州王成璟网络科技有限公司旗下赣州提速啦网络科技有限公司运营 投资1000万人民币 在美国Cera 香港CTG 香港Cera 国内 杭州 宿迁 浙江 赣州 南昌 大连 辽宁 扬州 等地区建立数据中心 正规持有IDC ISP CDN 云牌照 公司。公司购买产品支持3天内退款 超过3天步退款政策。提速啦的市场定位提速啦主...
如果我们较早关注NameCheap商家的朋友应该记得前几年商家黑色星期五和网络星期一的时候大促采用的闪购活动,每一个小时轮番变化一次促销活动而且限量的。那时候会导致拥挤官网打不开迟缓的问题。从去年开始,包括今年,NameCheap商家比较直接的告诉你黑色星期五和网络星期一为期6天的活动。没有给你限量的活动,只有限时六天,这个是到11月29日。如果我们有需要新注册、转入域名的可以参加,优惠力度还是比...
今天看到一个网友从原来虚拟主机准备转移至服务器管理自己的业务。这里问到虚拟主机和服务器到底有什么不同,需要用到哪些工具软件。那准备在下班之间稍微摸鱼一下整理我们服务器安装环境和运维管理中常见需要用到的软件工具推荐。第一、系统镜像软件一般来说,我们云服务器或者独立服务器都是有自带镜像的。我们只需要选择镜像安装就可以,比如有 Windows和Linux。但是有些时候我们可能需要自定义镜像的高级玩法,这...