025-缓存Cache

如果每次进入页面的时候都查询数据库生成页面内容的话,如果访问量非常大,则网站性能会非常差。而如果只有第一次访问的时候才查询数据库生成页面内容,以后都直接输出内容,则能提高系统性能。这样无论有多少人访问都只访问一次数据库,数据库压力不变。
缓存(Cache)是一种用空间换取时间的技术,存在于计算机中很多地方,用来将一些慢速设备中的常用数据保存在快速设备中,取数据的时候直接从快速设备中取。比如CPU二级缓存、内存、windows文件读取缓存。
缓存存在失效的问题:为了保证从缓存中读取数据和慢速数据(数据库)中数据一致,则需要在慢速数据(数据库)中对应的数据发生变化的时候,清除缓存中相应的数据。
缓存是改进网站性能的第一个手段,就像索引是改进数据库性能的第一个手段一样。ASP.net缓存主要分为:页面缓存(中庸)、数据源缓存(最不灵活的)、数据缓存(灵活)这三种主要类型。

1.缓存可以提高数据访问性能,原因是缓存的数据都在内存中。避免了磁盘I/O操作,或者数据库的网络连接等。
2.缓存的数据,必须有一定的过期策略,否则实际的数据发生改变后,对应的缓存还是旧数据,就造成了数据不一致的问题。
3.什么情况下才用缓存?
1>访问的数据不会发生改变,或者是很少发生变化。
2>数据频繁被访问。

直接使用Cache

1>直接使用Cache["content"],缓存与Session不同,所有用户都可以共享。永不过期,由服务器自己维护,当内存不够时,会将老的缓存释放掉。
2>设置绝对过期日期。Cache.Insert("nowTime", DateTime.Now, null, DateTime.Now.AddSeconds(7), TimeSpan.Zero);
3>设置滑动过期日期: Cache.Insert("nowTime", DateTime.Now, null, DateTime.MaxValue, TimeSpan.FromSeconds(5));

if (Cache["nowTime"] == null)
{
Cache.Insert("nowTime", DateTime.Now, null, DateTime.MaxValue, TimeSpan.FromSeconds(5));
}
else
{
Response.Write("缓存中的时间:" + Cache["nowTime"]);
}
----------------------------------------------------------

if (Cache["time"] == null)
{
Cache["time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
Response.Write(Cache["time"]);
----------------------------------------------------------
if (Cache["time"] == null)
{
Cache.Insert("time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), null, DateTime.Now.AddSeconds(10), TimeSpan.Zero);
}
Response.Write(Cache["time"]);
----------------------------------------------------------
if (Cache["time"] == null)
{
Cache.Insert("time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), null, DateTime.MaxValue, TimeSpan.FromSeconds(5));
}
Response.Write(Cache["time"]);
----------------------------------------------------------

页面缓存

给页面添加<%@ OutputCache Duration=“15” VaryByParam=“none”%>标签就可以启用页面缓存,这样整个页面的内容都会被缓存,页面中的ASP.Net代码、数据源在缓存期间都不会被运行,而是直接输出缓存的页面内容。 Duration表示缓存时间,以秒为单位,超过这个时间则缓存失效,再次生成以后会再缓存15秒,以此类推。在Page_Load处设置断点、修改数据库数据测试。这个缓存是在服务器缓存的,不是在客户端,因为用HttpWatch还是能看到向服务器提交的请求的,只不过服务器看到有缓存就没有再执行页面类。一般只有看帖、看新闻、看视频的页面才缓存,CUD的页面没必要缓存。
缓存是针对所有这个页面的访问者。这样1个访问者和1万个访问者、一次访问和100万次访问对数据库的压力是一样的。
对于看新闻页面来讲,如果如上设置的话,则会缓存在第一个看到的新闻,因为?id=2、?id=3只是页面的不同参数而已,为了能让不同的新闻各自缓存,因此可以设置VaryByParam=“id”,表示对于相同页面的不同的id参数进行单独缓存。如果有多个确定缓存的参数,则将参数名用分号隔开即可,比如VaryByParam=“id;number”。测试。缓存可能会有过期数据的问题,因此根据需求选用。
如果想让任何不同的查询字符串都创建不同的缓存,则设置VaryByParam="*",一般情况下设置“*”就足够。
在WebUserControl中也可以像页面缓存一样设置控件的缓存。

id;name 组合缓存条件:只有两个参数的值组成的字符不一样的时候,才产生缓存
VaryByParam:分号分隔的字符串列表,用于使输出缓存发生变化。默认情况下,这些字符串对应于使用 GET 方法属性发送的查询字符串值,或者使用 POST 方法发送的参数。 将该属性设置为多个参数时,对于每个指定参数组合,输出缓存都包含一个不同版本的请求文档。可能的值包括 none、星号 ( *) 以及任何有效的查询字符串或 POST 参数名称。

<%@ OutputCache Duration="10" VaryByParam="*" %>
Duration="10",表示缓存时间10秒,10秒后过期(绝对过期)。
VaryByParam="*" ,表示按每次请求的参数不同,为每个不同的请求进行缓存。VaryByParam="none" 表示为所有的请求(无论参数是否一致)都只建立一个缓存。
VaryByParam="id"
VaryByParam="id;name"

数据源缓存

演示手动绑定数据的时候通过Cache[]把List缓存,设置缓存时间。
设定ObjectDataSource的CacheDuration(缓存时间:秒),EnableCaching=true。设置CacheExpirationPolicy=Absolute,该属性(过期策略)。这样每隔CacheDuration指定的时间段才调用SelectMethod指定的方法来执行数据库查询,其他时候都是直接返回缓存的数据。取数据的过程缓存,在缓存期间,绑定控件向ObjectDataSource要数据, ObjectDataSource直接将缓存的数据返回给控件,不再去向TypeName指向的类要数据。

缓存固定的时间适用于首页、文章列表等访问频繁的页面,对于看贴页面则不适合,假设有100万个帖子,如果每个帖子都是固定缓存1小时的话,假设一小时之内有10万个帖子被看了,那么就要缓存十万个帖子,非常占用内存,因为“百年一看”的“坟帖”偶然被访问一次也缓存一个小时,占用内存。这时候可以采用“滑动窗口(sliding)”策略,比如帖子缓存10分钟,如果10分钟之内又访问了,则缓存的失效时间修改为从被访问这一刻起的10分钟之后,以此类推。这样经常访问的帖子就可以“长期缓存”,而不经常访问的帖子也不会因为偶然访问而长期占用缓存。设置方法,数据源:CacheExpirationPolicy="Sliding"。面试可聊。todo:貌似滑动有问题。不是问题,Sliding只是策略,服务器会参考。

if (Cache["PersonList"] == null)
{
NewPersonBll bll = new NewPersonBll();
IEnumerable<NewPerson> list = bll.GetAll();
Cache["PersonList"] = list;
}

this.Repeater1.DataSource = Cache["PersonList"];
this.Repeater1.DataBind();

<asp:Repeater ID="Repeater1" runat="server" DataSourceID="ObjectDataSource1">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%#Eval("UName")%></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="ObjectDataSource1" CacheDuration="10" EnableCaching="true" CacheExpirationPolicy="Sliding" runat="server" SelectMethod="GetAll"
TypeName="Aspx.CRUD.BLL.NewPersonBll">
</asp:ObjectDataSource>

配置IIS输出缓存

选择IIS→网站→输出缓存→添加

内核缓存和IIS 7输出缓存
当使用服务器上的输出缓存时,也可以使用内核缓存和IIS 7输出缓存。IIS 7首先引入输出缓存,但IIS6也已经支持内核缓存。从这些缓存中响应请求要比从ASP.NET输出缓存中快,因为它们是集成在IIS中的。下面是工作原理。

当一个新的请求到达web服务器时,最先由内核驱动http.sys处理。这个驱动首先尝试从内核缓存中响应请求。如果不能,它会将请求发送到IIS的一个监听线程端口。这个IIS线程试图从IIS 7的输出缓存中响应请求。如果不能,将请求转交ASP.NET,这会激活另一个线程处理请求。ASP.NET尝试从它自己的缓存中响应请求,如果不能,再生成输出。结果会发送给第三个线程,再发送给浏览器。

这意味着,如果可以从内核缓存中提供文件,可以节省三个线程切换和切换到用户模式的开销。这使得从内核缓存中提供文件非常快。IIS 7输出缓存需要一个线程切换和切换到用户模式,但仍然要比ASP.NET缓存快。

缓存依赖,不是依赖于时间

依赖于文件内容CacheDependency cDep = new CacheDependency(filePath);
依赖于数据库内容(轮询机制/通知机制)(不讲)
一:轮询机制 –fw主动到数据库检查数据是否改变
1.使用C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727中的aspnet_regsql.exe:
注册:aspnet_regsql -S . -E -ed -d 数据库名 -et -t 表名
删除:aspnet_regsql -S . -E -d 数据库名 -dt -t 表名
取消数据库缓存依赖: aspnet_regsql -S . -E -dd 数据库名
数据库名 列出已注册表:aspnet_regsql -S . -E -d 数据库名 -lt
2.配置web.config(见备注)
3.数据库依赖对象
SqlCacheDependency cDep = new SqlCacheDependency("GSSMS", "Students");

缓存依赖文件
if (Cache["time"] == null)
{
Cache.Insert("time", DateTime.Now, new System.Web.Caching.CacheDependency(Request.MapPath("~/TextFile1.txt")));
}
Response.Write(Cache["time"]);

1.依赖于文件

System.Web.Caching.CacheDependency cDep = new System.Web.Caching.CacheDependency(filePath);
Cache.Add("fmsg", msg, cDep, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, RemovedCallback);

if (Cache["Time"] == null)
{
Cache.Insert("Time", DateTime.Now, new System.Web.Caching.CacheDependency(Server.MapPath("userfile.txt")));
}
Response.Write(Cache["Time"].ToString());

aspnet_regsql -S . -E(集成登陆)/-U sa -P 123 -ed(启动/-dd关闭) -d(数据库名) GSSMS -et(指定缓存依赖的表名/-dt禁用表名) -t(表名) Aticle
2.依赖于数据库的web.config配置
<system.web>
<caching>
<sqlCacheDependency enabled="true">
<databases>
<add name="GSSMS" connectionStringName="conStr2" pollTime="15000"/>
</databases>
</sqlCacheDependency>
</caching>

依赖数据库改变,数据库缓存依赖
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regsql.exe
1、数据库缓存依赖
-S服务器名称 -E集成身份验证 -ed启动 -d数据库名称 -et指定缓冲依赖的表名 -t表名
在vs2010的命令提示符中运行(切换到aspnet_regsql.exe所在的目录)
aspnet_regsql -S steve-pc -E -ed -d apsxDb -et -t TblComments

缓存依赖禁用该数据库
aspnet_regsql -S steve-pc -E -dd -d apsxDb

2、依赖于数据库的web.config配置
<system.web>
<caching>
<sqlCacheDependency enabled="true" pollTime="500">
<databases>
<add name="ccdb_msdb" connectionStringName="mssqlserver_cache"/>
</databases>
</sqlCacheDependency>
</caching>
</system.web>
<!--
pollTime, 可选的 Int32 属性。
设置 SqlCacheDependency 类实例轮询数据库表更改的频率。 此值对应于连续两次轮询之间的毫秒数。不能将其设置为小于 500 毫秒的值。默认值为 1 分钟。
-->

3、
System.Web.Caching.SqlCacheDependency dep = new System.Web.Caching.SqlCacheDependency("ccdb_msdb", "NewPerson");
Cache.Insert("list", list, dep, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration);

缓存(笔记)
-》需求:当频繁使用某个数据时,总是从源来获取,既浪费服务器资源,又浪费浏览者时间
将这些数据直接存到服务器内存中,用的时候直接获取
-》应用场景:使用频繁,改变小,读取速度慢
-》Cache对象是Page对象的一个属性,类型为键值对集合
写:Cache["键"]=值
读:Cache["键"]返回值
-》过期时间:缓存会一直存在于服务器中,直到应用程序关闭
使用Cache.Insert(键,值,null,绝对过期时间,滑动过期时间)来设置
如果使用绝对过期时间,则将滑动过期时间设置为TimeSpan.Zero
如果使用滑动过期时间,则将绝对过期时间设置为DataTime.MaxValue
-》页面缓存
如果页面被缓存,执行到第11、12事件间,会直接获取对象,后续处理不再执行
可以为页面设置缓存依赖,指令:<%@OutputCache Duration="8" VaryByParam="缓存依据" />
VaryByParam表示缓存依据,值为:none,*,参数名称
多个参数时,可以使用分号";"进行分隔
Duration表示缓存时间,单位为秒
示例:在页面上输出当前时间,刷新查看是否每次都执行
-》控件缓存:对于数据源控件,可以使用缓存功能
EnableCaching="true"
CacheDuration="5"
CacheExpirationPolicy="Sliding"
-》静态页面不被.net处理,如果希望缓存,可以在iis中进行设置
点击缓存-》添加,添加扩展名,勾选“用户模块”、“内核模块”
可以分别设置缓存时间
-》缓存依赖:除了以时间的方式可以让缓存过期之外,还可以依赖于文件、数据库,相关设置参考ppt操作一遍即可

WriteCache.aspx

 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WriteCache.aspx.cs" Inherits="t2_Cache.WriteCache" %>

 <!DOCTYPE html>

 <html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Write" />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<br />
<a href="ReadCache.aspx">ReadCache.aspx</a>
</div>
</form>
</body>
</html>

WriteCache.aspx.cs

     public partial class WriteCache : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{ } protected void Button1_Click(object sender, EventArgs e)
{
//Cache.Insert("xlb",TextBox1.Text,null,new DateTime(2015,1,1), TimeSpan.Zero); Cache.Insert("xlb", TextBox1.Text, null, DateTime.MaxValue, TimeSpan.FromSeconds());
}
}

ReadCache.aspx

 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReadCache.aspx.cs" Inherits="t2_Cache.ReadCache" %>

 <!DOCTYPE html>

 <html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Read" />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</div>
</form>
</body>
</html>

ReadCache.aspx.cs

     public partial class ReadCache : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{ } protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = Cache["xlb"].ToString();
}
}

PageCache.aspx(页面缓存)

 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="PageCache.aspx.cs" Inherits="t2_Cache.PageCache" %>

 <%@ OutputCache Duration="10" VaryByParam="*" %>
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<%=DateTime.Now.ToString() %>
<hr />
<a href="?id=1">id=1</a>
<a href="?id=2">id=2</a>
<a href="?id=1&page=1">id=1&page=1</a>
<a href="?id=1&page=2">id=1&page=2</a>
</div>
</form>
</body>
</html>

ControllCache.aspx(服务器控件缓存)

 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ControllCache.aspx.cs" Inherits="t2_Cache.ControllCache" %>

 <!DOCTYPE html>

 <html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1">
<ItemTemplate>
<%#Eval("ProvinceId") %>
</ItemTemplate>
</asp:Repeater>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:web1ConnectionString %>" SelectCommand="SELECT * FROM [S_Province]" EnableCaching="True"></asp:SqlDataSource>
</div>
</form>
</body>
</html>
上一篇:Xmpp实现简单聊天系列 --- ①openfire部署


下一篇:ibatis