随笔-5  评论-5  文章-0  trackbacks-0
  2008年4月16日
 

Scott MitchellDataSource系列之七声明式缓存数据

Accessing and Updating Data in ASP.NET 2.0: Declaratively Caching Data
By Scott Mitchell

原文地址:Declaratively Caching Data

前言
ASP.NET 2.0
数据源控件提供一种声明式访问和处理数据的手段。简单地配置一下控件的几个属性就可将数据绑定到数据控件.这样甚至不用手写一行代码,就实现了检索和处理数据。

除了可以声明式处理数据,这些数据源控件还可以实现声明式缓存数据. 缓存通常应用于一些数据驱动的应用程序以提高性能,它的基本工作原理是将数据存储到内存中,这样可以大大提高数据的访问效率. ASP.NET支持数据缓存,可以通过编程方式来访问存储于其中的数据库查询结果.可以到 ASP.NET中的缓存 查看有关缓存以及ASP.NET的其他缓存机制.

值得一提的是,数据源控件提供声明式访问数据缓冲区. 只需简单地设置几个属性,数据源控件就会轻松地将检索到的数据存储到数据缓冲区.然后,当再次向数据源检索数据时, 它们就可以直接从缓存中读取,而不是再次到数据库中检索.本文将介绍如何使用数据源控件的缓存特性.

缓存快速入门
缓存是一种提高性能的技术,它把数据从比较昂贵的数据存储转到相对低廉的存储形式.这里我所说的昂贵是指处理数据所带来的性能损失,”数据存储是指数据存储的方式,比如数据库,文件或者内存等.典型的缓存案例是将从数据库检索到的数据存储到应用程序内存中,因为应用程序从内存中读取数据的速度要比远程读取数据库快好几个数量级.

缓存技术也有一些局限性.效率较高的数据存储占用的空间较小. 也就是说, 尽管数据库中有大量的数据,但能够存储在应用程序缓存中的只占其中很小的一部分. 因此,并非所有数据都可以实现缓存.而且当向缓存区写入数据时,有些其他缓存数据就要被清除,腾出点地儿来.

而且, 缓存会强制断开应用程序“看到的”数据和真实的数据源之间的连接。如果真实的数据源被修改或删除,使用缓存数据的应用程序将不会判别出它持有的数据已经作废,除非它再次访问数据源。因此,通常情况下数据在预定的时间内缓存,然后会自动被清除。这样便存在着数据过期的一个时间上限。 (ASP.NET 2.0 支持 SQL 缓存依赖,该技术可以更“主动”地判断缓存数据是否过期。本文对SQL 缓存依赖不作深入探讨,详情请查看文末的“延伸阅读”。)

缓存是ASP.NET 应用程序中经常使用的技术之一,它是将数据存储在内存中,可以通过Cache对象来访问。缓存提供类似字典的访问机制。在缓存区添加一个新项,只需为该项指定一个string类型的键。同理,要从缓存中获取数据,只需通过它的键来获得。下面的代码段展示了如何读写缓存中的数据:

// C#

Cache["key"] = ObjectToCache; // 写入缓存

object myData = Cache["key"]; // 从缓存中读出

' VB

Cache("key") = ObjectToCache         ' 写入缓存

Dim myData As Object = Cache("key") ' 从缓存中读出

数据源控件检索缓存数据
ObjectDataSource, SqlDataSource, AccessDataSource
以及 XmlDataSource这几个控件都包含如下支持缓存的几个主要属性。缓存是自动发生的,无须开发人员编写代码。它们的主要属性如下:

  • EnableCaching一个布尔值,表示是否应用缓存,默认为False。可以将其设置为True来启用缓存。
  • CacheDuration一个Integer类型的值,获取或设置以秒为单位的一段时间。它是数据源控件缓存Select方法所检索到的数据的时间
  • CacheExpirationPolicy - 获取或设置缓存的到期行为,该行为与持续时间组合在一起可以描述数据源控件所用缓存的行为,可以设置为AbsoluteSlidingAbsolute 表示缓存项从数据存入缓存区开始经过CacheDuration秒后被清除;Sliding表示缓存项自缓存数据被访问的时间开始,经过CacheDuration秒后被清除,它的默认值是Absolute
  • CacheKeyDependency是个String类型的值,表示获取或设置一个用户定义的键依赖项,该键依赖项链接到数据源控件创建的所有数据缓存对象。当键到期时,所有缓存对象都显式到期

如果启用了SQL缓存依赖,那么就要使用SqlDataSourceObjectDataSource控件的SqlCacheDependency属性。还有一点要记住, AccessDataSource控件没有这一属性,如果试图使用将会引发一个NotSupportedException异常。最后还要记住,若要这些数据源控件启用缓存,必须将EnableCaching属性设为True,并且通过CacheDuration指定一个过期时间或者指定一下SQL缓存依赖。

下面的声明式代码段展示了一个启用缓存并将过期时间设为30秒的AccessDataSource 控件(在本文最后提供下载的示例代码中还有更多相关demo)

<asp:AccessDataSource ID="ProductsDataSource" runat="server"

    DataFile="~/App_Data/Northwind.mdb"

    SelectCommand="SELECT * FROM [Products]"

    CacheDuration="30"

    EnableCaching="True">

</asp:AccessDataSource>

当数据控件(比如GridView)触发了该AccessDataSource控件的Select方法后, AccessDataSource 会首先查看数据是否在缓存区。如果不是,它才会连接Microsoft Access数据库(Northwind.mdb),并执行SelectCommand的查询,然后它会把7ED3果存储到缓存区,再将其交给数据控件。假设5秒钟后另一个用户访问该页面,数据控件会再次向AccessDataSource 发出数据请求,不过这次数据将会在缓存区。因此, AccessDataSource 无需访问数据库而直接把缓存中的数据交给数据控件。但是30秒钟后,缓存区中的数据将会被清除,后续的数据请求将会连接到数据库。

数据源实现数据缓存之细节探究
当启用了缓存的数据源控件被触发了Select方法时,它会首先检查数据是否存放在缓存区。之前已经提过,缓存中的数据项是通过一个string类型的键来访问的,数据源控件使用的这个键值是它一系列属性的集合。比如SqlDataSource,它包括CacheDuration, CacheExpirationPolicy, ConnectionString, SelectCommand, 以及SelectParameters这些属性的值。这样可以保证每个连接,每个SELECT查询及其查询的参数名和值(如果有)的唯一性。

在缓存区发现了数据项后,数据源控件将会返回这些数据,不去触发它的Selecting事件。我在了解数据源控件的事件机制这篇文章中已经提过,在数据源控件触发Select方法并从数据库中检索出数据后,Selecting事件才会被激发。

而如果在缓存中没有找到数据项,数据源控件就会按照常规方式进行查询:Selecting事件被触发,然后访问数据库,检索数据,最后是触发Selected事件。但是在数据返回前,数据源控件会首先将其添加到缓存,过程如同上面的介绍。

下面的流程图描述了ObjectDataSource的缓存工作流程,AccessDataSource, SqlDataSource XmlDataSource控件也都一样。注意如果数据项在缓存中,那么Selecting事件便不会被触发。


可以看出,
Selecting事件只有从数据库中访问数据时才会发生,这也是上一次缓存发生的时间。文末的代码示例使用了一个Label 控件,该控件的值根据Selecting事件的每次发生而更改为当前的日期和时间,因此它可以显示缓存最近的一次修改发生的时间。尽管最终用户可能不需要也没必要看到这种信息,但这对页面开发人员却非常有用,因为它可以显示缓存发生的时间以及什么行为可以使缓存比预期时间更早地被清除。

清除缓存中的数据
缓存的一大弊端就是过期数据,短时间的过期策略可以有效地限定潜在的过期数据的持续时间。也有其他的方法来强行将一个数据项从缓存中清除,这就是数据源控件的Insert, Update, Delete事件,他们一旦被调用,控件将会自动清除掉它们的缓存数据。在接下来的文章中,我们会详细探讨数据源控件中可用的这些数据修改方法。总之,这些方法修改数据库中的数据,并且正像他们的名称表示的那样可以声明式地配置。当这些方法执行时,数据源控件修改的是数据库中的数据,所以数据源控件将会清除缓存,因为缓存数据已经过期了。你可以在文末的代码示例中查看。

还可以通过编程方式使用CacheKeyDependency属性清除数据源控件的缓存数据。将该属性的值设置为缓存数据中的某个键值,然后,只需修改一下CacheKeyDependency的值即可清除该数据源控件中的缓存数据。

更改数据源控件的CacheKeyDependency属性为你想设为依赖项的缓存键的名称,比如可以将该属性的值设为一个过时的变量:

<asp:AccessDataSource ID="ProductsDataSource" runat="server"

    DataFile="~/App_Data/Northwind.mdb"

    SelectCommand="SELECT * FROM [Products]"

    CacheDuration="30"

   EnableCaching="True"

    CacheKeyDependency="ProductsDependency">

</asp:AccessDataSource>

接着,必须解决的是该确定是否有数据项存在于缓存中。否则一旦有数据项添加到缓存时就会清除数据源控件的原有缓存数据。在Page_Load事件中,判断该项是否存在于缓存;如果没有,则添加之:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load

    '添加缓存项,如果需要的话

    If Cache(ProductsDataSource.CacheKeyDependency) Is Nothing Then

        Cache(ProductsDataSource.CacheKeyDependency) = DateTime.Now

    End If

End Sub

这里我将DateTime.Now赋给缓存项,不过你可以使用其他任意值.DateTime.Now是个不错的选择,因为它可以表示该缓存项上次被访问的时间.

若要通过编程方式清除缓存数据,只需修改一下Cache(ProductsDataSource.CacheKeyDependency)的缓存值即可,比方说修改为当前的日期和时间(Cache(ProductsDataSource.CacheKeyDependency) = DateTime.Now). 本文最后附上的demo中,页面上的按钮被点击后,触发事件将Cache(ProductsDataSource.CacheKeyDependency)的值修改为当前的日期和时间,这样就可以清除缓存数据了.就是这么简单!

小结
数据源控件访问和操作数据简单得只需设置几个属性,通常情况下无需手写代码。在本文中我们可以看到,声明式同样适用于缓存。在数据源控件中应用缓存很简单,只需将该控件的EnableCaching属性设为True,将CacheDuration属性设置为数据缓存持续的时间()SqlDataSourceObjectDataSource控件还支持缓存依赖,我将在以后的文章中介绍这些特性。

祝编程愉快!

· By Scott Mitchell

延伸阅读

· 缓存之于性能

· ASP.NET 2.0缓存特 (包括SQL缓存依赖)

·  ASP.NET 缓存:方法和最佳实践

· [视频] ASP.NET2.0中的缓存

附件

· 下载本文的示例代码

posted @ 2008-04-16 16:29 小白杨 阅读(104) | 评论 (0)编辑
  2008年2月20日
由于项目要定期导出mysql数据库,于是写了个脚本。

该脚本导出的文件名格式为bak-[年-月-日-时-分-秒.厘秒]-db.sql,例如bak-[2008-02-20-10-27-06.58]-db.sql,因此每次导出的文件名都不重复。导出的文本文件将被保存到当月的文件夹内,每月1号会自动创建本月的文件夹。


注意的几点
1.该脚本仅在Windows XP+SP2中文版操作系统下测试可用,在Windows Server 2003环境下运行前,请先在命令行中键入echo %date%%time%,查看日期格式,如果是“yyyy-mm-dd 星期N 时:分:秒.厘秒”,例如“2008-02-20 星期三10:30:43.90”,则可用。

2.添加到任务计划时将脚本最后一行的@pause删除(带上pause仅为测试时方便查看错误信息,并且dos窗口不关闭)。

附:脚本

 1::文件名:任务导出.bat
 2::作者:daybug      创建日期:2008-2-20
 3::功能:将数据库备份导出到以当前日期和时间命名的文件中,并保存到该月的文件夹下。
 4::注意:脚本仅在Windows XP中文版操作系统下测试可用,其他环境下请先测试是否可用。
 5
 6::启动mysql服务
 7@net start mysql
 8::根据当前的日期时间,生成备份的文件名。
 9@set FileName=bak-[%date:~0,10%-%time:~0,2%-%time:~3,2%-%time:~6,2%.%time:~9,2%]-warmsupply.sql
10::生成当月的文件夹名
11@set DirName=%date:~0,7%
12::每月1号创建新的文件夹
13@if %date:~8,2%==01 (md %DirName%)
14::如果没有本月文件夹(初次运行时如果不是1号),则创建本月文件夹
15@if not exist %DirName% (md %DirName%)
16::执行导出
17@mysqldump --default-character-set=gbk -uUSERNAME -pPASSWORD yourdb >%DirName%\%FileName%
18@echo 导出成功
19@pause
20
posted @ 2008-02-20 19:56 小白杨 阅读(186) | 评论 (0)编辑
  2007年8月21日
     摘要: 使用XmlDataSource控件访问XML数据Accessing and Updating Data in ASP.NET 2.0: Retrieving XML Data with XmlDataSource Control By Scott Mitchell 原文地址:http:/aspnet.4guysfromrolla.com/articles/092706-1.aspx 序: ASP.... 阅读全文
posted @ 2007-08-21 12:33 小白杨 阅读(414) | 评论 (2)编辑
  2007年5月8日

刚学到的,并不新鲜;
里面的两个表示例是在网上随便找的,希望没有侵权.

-----------------------sql语句的几个知识点-----------------------------

--以如下两个表为例
--
------------------------ 创建表author ---------------------------------
create table author(
id                 
int not     null,
AuthorName         
varchar(20null,
address         
varchar(50null,
introduction     
ntext         null 


--------------------------- 创建表article---------------------------------
create table article(
id             
int identity(1,1)     not null,
authorId     
int                 not null,
title         
varchar(40),        not null,
createdDate 
datetime
)
--------------------------------------------------------------------------------
--
1,为author表添加主键信息
alter table author
add constraint pk_author  --这个命名并没有多大的实际意义
primary key(id)

--2,外键
--
设置表article中的authorId为外键,参照author表的主键id字段
alter table article add constraint fk_article_author--这个命名也是一样,没有多大实际意义
foreign key (authorId)
references author(id) 
on update cascade
on delete cascade
--上面on update cascade,on delete cascade两个选项,
--
指明以后author表的id字段有delete,update操作时,
--
article表中的iauthorID也会被级联删除或更新.

--3删除约束
alter table article drop constraint fk_article_author
--这里的命名就是上面新建约束时的命名

--新建某个表时,有时需要先检查一下是否已经建了这个表,如已建了,则删除之
if exists

  
select id from sysobjects 
  
where id = object_id('author')        --如果系统表中有这个对象
  --and sysstat & 15 = 3                            --并且这个对象类型是"表"(Sybase中的方式)
  and objectproperty(id,'istable'= 1    --并且这个对象类型是"表"(SQL Server中的方式)
)
drop table author                --那么删除之
go
--然后新建该表
create table author(
id                 
int not     null,
AuthorName         
varchar(20null,
address         
varchar(50null,
introduction     
ntext         null 
)
go


--这里我发现一个有意思的问题.开始我使用系统表sysobjects里“sysstat & 15 = 3"来判断某个表是否已经存在;
--
后来想到这是我在sybase项目里先使用的,不知道在SQL Server里是不是有效.于是又找了个SQL Server里常用的方法
--
就是判断系统表sysobjects里的objectproperty(id,'istable') 值是否为1,如果是1,那么这就是"表";否则这就不是表.
--
于是我仔细看了下M$ SQL Server里的系统表sysobjects,发现里面也有sysstat列,那么使用“sysstat & 15 = 3"来判断是否为表,应该也可以吧?

--于是打开查询分析器,use NorthWind,然后
select name from sysobjects
where sysstat & 15 = 3

--结果正是NorthWind里的各个表
--
--Orders
--
--Products
--
--Order Details
--
--CustomerCustomerDemo
--
--CustomerDemographics
--
--Region
--
--Territories
--
--EmployeeTerritories
--
--Employees
--
--Categories
--
--Customers
--
--Shippers
--
--Suppliers

--那么刚才提到的系统表sysobjects里的objectproperty(id,'istable') 值是否为1的方法呢?
--
试一下吧.
select name from sysobjects
where objectproperty(id,'istable'= 1
--啊!返回这么多!
/*
 Categories
CustomerCustomerDemo
CustomerDemographics
Customers
Employees
EmployeeTerritories
Order Details
Orders
Products
Region
Shippers
Suppliers
syscolumns
syscomments
sysdepends
sysfilegroups
sysfiles
sysfiles1
sysforeignkeys
sysfulltextcatalogs
sysfulltextnotify
sysindexes
sysindexkeys
sysmembers
sysobjects
syspermissions
sysproperties
sysprotects
sysreferences
systypes
sysusers
Territories 
*/
--仔细看下,其实这里面包含了系统表.
--
------------------------------------------------------------------
--
由此看来,"sysstat & 15 = 3"不仅在Sybase中可以使用,在M$ SQL Server里也可以;而且在这里更合适.因为我们操作的都不是系统表.
--
至于objectproperty(id,'istable')方法,我查了一下msdn,具体情况见http://msdn2.microsoft.com/zh-cn/library/ms176105.aspx.
--
objectproperty函数的第二个参数可以是isSystemTable用来判断对象是否系统表.
--
这下好说了,且看
select name from sysobjects
where objectproperty(id,'istable'= 1
and objectproperty(id,'isSystemTable'= 0
--输出
/*
 Categories
CustomerCustomerDemo
CustomerDemographics
Customers
Employees
EmployeeTerritories
Order Details
Orders
Products
Region
Shippers
Suppliers
Territories 
*/
--搞定!
--
-------------------------------------------------------------------------------------
--
看来SQL实在是精妙而又庞大,我所能理解的无非那几句create,update,delete,select而已,
--
不过是浩瀚的知识海洋中的一滴水,九牛之一毛,树林之一木.
--
加油!
posted @ 2007-05-08 17:03 小白杨 阅读(103) | 评论 (0)编辑
  2006年11月29日
     摘要: ASP.NET 2.0中新近引入了一系列的用来访问和更新数据的WEB控件。这些控件的出现使得网页开发人员可以以声明式的编程方式访问并对数据进行操作,摈弃了原来那种编写数据访问代码的方式。本篇文章是我翻译的关于ASP.NET 2.0中最新的数据源控件文章系列专题中的一个.主要介绍了如何访问数据库中的数据-- 展示如何通过SqlDataSource以及AccessDataSource控件从一个关系形数据库中查询并获得数据.

  阅读全文
posted @ 2006-11-29 21:35 小白杨 阅读(2102) | 评论 (3)编辑