在ASP.NET 2.0中操作数据之五十六:使用ObjectDataS
本文将深入ASP.NET 2.0中ObjectDataSource的内置缓存功能。通过简单的配置,我们可以轻松缓存ObjectDataSource调用SelectMethod方法获取的数据,从而提高应用程序的性能。
一、引言
在计算机科学领域,缓存是将所需的数据或信息备份在某个地方,以便快速访问的过程。对于数据驱动的程序而言,大部分时间都花费在数据查询上。为了提高这类程序的性能,一种常见做法是将查询结果存储在程序存储器中。
ASP.NET 2.0提供了多种缓存方式,包括页面和用户控件的输出缓存。我们还可以通过ObjectDataSource控件在控件级别对数据进行缓存。ASP.NET的数据缓存提供了丰富的缓存接口(caching API),供页面开发人员通过编程缓存对象。本文将详细介绍ObjectDataSource的缓存属性,并在接下来的几篇文章中数据缓存的其他方面,包括如何在启动时缓存application-wide数据以及使用SQL缓存依赖项刷新缓存数据。
二、主要缓存要点
缓存通过将数据的副本放置在一个易于快速访问的位置,从而提高程序的总体性能。由于缓存的是数据的副本,因此当源数据发生变化时,副本不会同步更新。为了确保数据的准确性,页面开发人员需要制定清除缓存的标准。有两种常用的方法:
1. 时间基准:向内存中添加的条目只能在内存中存在固定或滑动的一段时间。例如,开发者可以设置一个时间间隔,如60秒。当条目添加到内存后,无论访问频率如何,60秒后都会被清除。如果是滑动处理,则当条目被访问一次后,未访问的时间一旦超过60秒,也会被清除。
2. 依赖基准:向内存中添加条目时,为其分配一个依赖项。当依赖项发生变化时,条目将被清除。依赖项可以是一个文件、另一个缓存条目或两者的组合,甚至是SQL缓存依赖项。当源数据发生变化时,它可以清除内存中的条目。
无论采用哪种标准,在条目被清除之前,我们都可以访问它。当内存达到其极限时,它会清除已有的条目,然后再添加新的条目。处理缓存数据时,重要的是要考虑到缓存数据可能被清除的可能性。在下一篇文章中,我们将考察从内存访问数据的模式。
三. 缓存的重要性和适用场景
缓存是一种提高程序性能的经济方法。正如Steven Smith在其文章《ASP.NET Caching: Techniques and Best Practices》中所阐述的:“缓存是获得‘上佳'性能的一种好方法,不需要太多的时间和分析。……存储器也便宜,要获得你期望的性能,靠缓存技术你需要花30秒;靠优化代码和数据库你可能要几天乃至几周时间……”
尽管缓存可以显著提高系统性能,但并不适用于所有应用程序,尤其是那些需要实时或频繁更新数据的程序。对于大多数程序而言,缓存仍然是适用的。关于ASP.NET 2.0中缓存的更多背景信息,请参阅ASP.NET 2.0 QuickStart Tutorials系列的Caching for Performance部分。
四、创建Caching页面
在我们开始之前,需要创建包括本文在内的最近四篇教程所需的页面。在项目创建一个名为“Caching”的文件夹。然后,为这个文件夹添加以下几个页面,并配置它们使用Site.master母板页:
1. Default.aspx
2. ObjectDataSource.aspx
3. FromTheArchitecture.aspx
4. AtApplicationStartup.aspx
5. SqlCacheDependencies.aspx
用户控件与网站地图的奇妙融合——以SectionLevelTutorialListing.ascx为例
让我们聚焦于一个名为SectionLevelTutorialListing.ascx的用户控件,它拥有强大的功能,能在设计模式中轻松拖放到Default.aspx页面上。为了让这些页面更加易于导航,我们需要将它们添加到Web.sitemap文件中。特别地,将它们放置在“处理二进制数据”节点之后。
Web.sitemap文件中的节点结构如下:首先是一个标题为“Caching”的主要节点,它的URL指向Caching文件夹下的Default.aspx页面,描述中提到将学习如何使用ASP.NET 2.0的缓存功能。接着,添加了几个子节点,每个节点都对应一个具体的缓存主题页面,如ObjectDataSource缓存、架构中的缓存、应用启动时缓存数据、使用SQL缓存依赖等。
完成Web.sitemap文件的更新后,让我们打开浏览器查看成果。左侧的菜单栏现在显示了Caching章节的相关文章,这一结构为用户提供了清晰的导航路径。我们称之为图3:网站地图包含了Caching章节的文章。
接下来,我们要在网页上展示产品。本文将如何使用ObjectDataSource控件内置的缓存功能。我们需要创建一个页面,使用ObjectDataSource控件调用ProductsBLL class类来获取产品信息,然后通过GridView控件展示这些信息。
打开Caching文件夹中的ObjectDataSource.aspx页面。在此页面上,从工具箱拖放一个GridView控件到页面,设置其ID为Products。接着,通过智能标签选择将其绑定到一个ObjectDataSource控件,ID为ProductsDataSource。此ObjectDataSource将使用ProductsBLL class类。
在这一步骤中,我们将创建一个可编辑的GridView控件。当ObjectDataSource控件中的缓存数据发生变化时,我们可以通过GridView的界面观察其影响。在SELECT标签中选择默认的GetProducts()方法,在UPDATE标签中选择接受特定输入参数的UpdateProduct()重载方法。这样,我们就能实时更新产品信息并反映在界面上。
这样的设置为用户提供了一个直观的方式,了解缓存数据如何影响网页展示,并能够在产品信息进行更改时及时作出响应。通过这种方式,我们能够为用户提供更丰富、更实时的在线体验。图5:在UPDATE标签里选择重载的UpdateProduct()方法
在完成数据源设置向导的过程中,我们需要进行一系列的关键操作。在INSERT和DELETE标签中,我们选择“(None)”,这是因为我们的目的只是针对产品数据进行更新操作。当“设置数据源向导”结束时,Visual Studio会自动为我们的ObjectDataSource控件设置OldValuesParameterFormatString属性为original_{0}。正如我们在之前的教程中所的,这个属性如果不进行适当的调整,可能会导致更新操作时发生错误。为了避免这种问题,我们应该将这个属性的值设置为{0}或者将其完全删除。
完成向导后,Visual Studio会自动将产品的所有数据列添加到GridView控件中。我们需要对部分列进行操作。除了ProductName、CategoryName和UnitPrice这三个列之外,其他的绑定列(BoundFields)都需要被删除。然后,我们将这三个列的HeaderText属性分别修改为“Product”,“Category”和“Price”,以提供更清晰的界面显示。由于ProductName是必需的字段,我们需要将ProductName列转换为模板列(TemplateField)。在EditItemTemplate中,我们需要添加一个RequiredFieldValidator控件以确保此字段在编辑时不会被留空。同样地,UnitPrice列也需要转换成模板列,并添加一个CompareValidator控件,以保证用户输入的是有效的货币值,且大于或等于0。
我们还可以对界面进行一些美化。例如,我们可以让UnitPrice的值居中显示,或者对UnitPrice的只读和编辑界面进行格式化的处理,使其更符合用户的需求和视觉体验。
在GridView的智能标签中,我们可以通过点击相关项来启动编辑、分页和排序功能。这使得数据的管理和展示更为灵活和便捷。
想要回顾如何自定义GridView的编辑界面吗?请查阅之前的文章第20章。在那章中,我们详细了如何优化GridView的编辑界面,以满足不同的需求。现在,让我们继续深入图6中的功能启用。
图6:启用GridView的编辑、排序、分页功能。这是一个强大的工具,允许用户根据自己的需求对数据进行实时的修改、排序和分页查看。通过启用这些功能,我们可以大大提高数据管理的效率和用户体验。经过精细化的修改和重构,GridView与ObjectDataSource的代码段呈现出了高度的专业性和细致的考虑。这个GridView控件负责展示产品的关键信息,仿佛是在进行一场SEO优化的精心布局,每个细节都被精心设计过。
我们看到GridView控件正在展示名为“Products”的数据集。它包含一些重要的属性,如产品名称(Product)、类别(Category)和价格(Price)。这个控件允许分页和排序,为用户提供了流畅且个性化的体验。它还内置了编辑按钮,允许用户直接编辑每一项产品的信息。
在产品名称这一列中,我们看到了一个典型的编辑模板字段(TemplateField)。在这个字段中,产品的名称既可以以标签(Label)的形式展示,也可以在编辑模式下以文本框(TextBox)的形式出现。为了确保用户输入的产品名称是有效的,这里还使用了一个必需字段验证器(RequiredFieldValidator)。
价格字段也是一个模板字段,它同样允许用户在编辑模式下进行修改。这里使用了货币格式化的文本框(TextBox),并要求用户输入一个有效的货币值。为了防止用户输入无效的数据,这里还使用了一个比较验证器(CompareValidator),确保输入的值大于或等于零。这个字段也设置了对齐方式为右对齐,以符合财务信息的展示习惯。
我们来看看ObjectDataSource控件的配置。这个控件作为GridView的数据源,负责提供数据以及处理数据的更新操作。在这里,它配置为使用名为“ProductsBLL”的业务逻辑层对象来提供数据。它也配置了更新方法(UpdateMethod)和更新参数(UpdateParameters),以便在需要更新数据时能够正确地传递参数。
这个GridView和ObjectDataSource的配置就像是一个精心设计的网站界面,不仅展示了产品的关键信息,也允许用户轻松地进行编辑和更新操作。就像图7所展示的,它为用户提供了一个清晰、直观且易于操作的界面,用于管理和编辑产品信息。几分钟页面测试:数据交互的
让我们花几分钟来测试这个页面,你将看到排序、分页和记录编辑等功能在实际操作中的流程。
图7:数据的初步展示
当你打开这个页面时,图7将显示每条记录的Name、Category和Price信息。这些数据的展示背后是ObjectDataSource在默默发挥作用。
ObjectDataSource的数据请求之旅
ID为Products的GridView控件通过调用名为ProductsDataSource的ObjectDataSource的Select()方法来获取数据。这个数据源进一步与业务逻辑层的ProductsBLL class进行交互,通过调用GetProducts()方法从数据访问层获取数据。数据访问层连接到Northwind数据库并执行预定义的SELECT查询。查询结果以NorthwindDataTable的形式返回,经过层层传递,最终被GridView控件编译为HTML呈现在浏览器上。
每当GridView需要绑定数据,如登录、页面间传递数据、在GridView内进行排序或编辑操作时,都会触发这一系列的数据请求流程。即使GridView的视图状态(View State)被禁用,每次页面回传时也会重新绑定GridView。我们可以选择显式地调用DataBind()方法来绑定GridView。
为了更好地理解数据检索的频率,我们在GridView上添加了一个Label控件(ID为ODSEvents)和一个Button控件(显示为“Postback”)。Label控件用于显示数据检索的状态信息。每当ObjectDataSource开始检索数据时,都会触发Selecting事件,我们可以在此事件处理器中显示相应的信息。例如,当点击“Postback”按钮时,Label控件会显示文本“Selecting event fired”。
ObjectDataSource缓存数据之旅的第四步
让我们深入理解并应用ObjectDataSource的数据缓存功能。只需简单设置几个属性,ObjectDataSource就可以自动缓存检索的数据。这些与缓存相关的属性包括:
1. EnableCaching:此属性必须设置为true,默认值为false。启用此属性后,ObjectDataSource将开始缓存数据。
2. CacheDuration:以秒为单位的缓存时间。当EnableCaching属性设置为true,并且CacheDuration设置为大于0的值时,ObjectDataSource才会缓存数据。
3. CacheExpirationPolicy:可设置为Absolute或Sliding。如果设置为Absolute,数据将在设定的秒数后过期;如果设置为Sliding,数据在一段时间内未被访问将会过期。默认值为Absolute。
4. CacheKeyDependency:使用该属性可以将ObjectDataSource的缓存条目与现有的缓存依赖项关联起来。这有助于在必要时清除缓存条目。
假设我们有一个名为ProductsDataSource的ObjectDataSource,现在我们想将其数据缓存时间设置为30秒。我们将其EnableCaching属性设置为true,CacheDuration属性设置为30秒,并且保持CacheExpirationPolicy为默认值Absolute。
当你首次访问页面时,由于数据尚未缓存,会出现文本“Selecting event fired”。当你执行诸如Postback、分页、排序、编辑或取消操作时,文本将不会显示,因为ObjectDataSource从缓存中获取数据,而不是重新检索。
30秒后,数据将从内存中清除,或者当你调用ObjectDataSource的Insert、Update或Delete方法时,数据也会被清除。ObjectDataSource将重新检索数据,触发Selecting事件,文本“Selecting event fired”将再次显示。然后,检索得到的数据将被重新缓存。
需要注意的是,如果你频繁地看到“Selecting event fired”文本的出现,可能是由于内存容量不足。如果ObjectDataSource无法缓存或只能偶尔缓存数据,建议关闭一些应用程序以释放内存并再次尝试。
图12揭示了ObjectDataSource的缓存流程。当文本“Selecting event fired”出现在屏幕上时,表示数据未在缓存中找到,必须进行检索。当文本消失时,表示数据已被缓存。从缓存获取所需数据时,无需执行任何数据查询。
每个ASP.NET应用程序都有其自己的数据缓存实例,所有页面和用户都可以访问。这意味着ObjectDataSource控件缓存的数据可供所有访问该页面的用户访问。为了验证这一点,可以在一个浏览器中打开ObjectDataSource.aspx页面。当首次访问该页面时,“Selecting event fired”文本将出现(假设之前的缓存数据已被清除)。然后,在另一个浏览器中输入相同的URL。在新浏览器中,不会显示“Selecting event fired”文本,因为它使用的是第一个浏览器页面的缓存数据。
通过合理配置ObjectDataSource的缓存属性,我们可以提高应用程序的性能并优化用户体验。当您向内存添加检索数据时,ObjectDataSource的关键角色就是缓存数据的使用和管理。它通过创建独特的Cache Key值来区分不同的数据缓存条目。这个Cache Key值包含多个属性的组合,如CacheDuration和CacheExpirationPolicy属性的值,业务对象的类型(由TypeName属性指定,如ProductsBLL),SelectMethod属性的值,以及SelectParameters中参数的name和values等。除此之外,StartRowIndex和MaximumRows属性也参与其中,以支持用户自定义的分页功能。
这些属性的组合形成了一个独特的缓存键值,为每一条缓存数据提供了唯一的标识。例如,在前面的教程中,我们使用了ProductsBLL类的GetProductsByCategoryID(categoryID)方法来获取特定类别的产品。如果一位用户在页面上查看了饮料类的产品信息(假设CategoryID值为1),ObjectDataSource在缓存这些数据时,会考虑到SelectParameters的值。这样,当另一位用户查看调味品类的产品信息时,他们各自看到的信息是独立的,不会被彼此的数据缓存所干扰。这是因为cache key包含了SelectParameters的值,使得ObjectDataSource能够区分不同类别的产品信息。
在实际应用中,我们可能会遇到数据更新不同步(Stale Data)的问题。当ObjectDataSource控件执行Insert、Update或Delete方法时,它会清除与这些操作相关的缓存条目,以确保数据的实时性。即使数据被更新,仍有可能出现显示“未更新数据”的情况。比如,当直接从数据库修改数据时(比如数据库管理员运行脚本修改数据),如果ObjectDataSource仍然使用旧的缓存数据,就可能出现这种情况。
让我们深入一种情况:即使调用ObjectDataSource的数据修改方法会清除匹配的缓存条目,但如果存在多个ObjectDataSources控件更新相同的数据但使用了不同的SelectMethods或SelectParameters,那么情况就会变得复杂。假设你有两个ObjectDataSources控件,它们更新同一行记录,但使用了不同的SelectMethods或不同的SelectParameters值创建不同的缓存键值。当第一个ObjectDataSource控件更新某一行记录并清除缓存数据时,第二个ObjectDataSource控件可能仍然使用旧的缓存数据来显示该行信息。这是因为它们的缓存键值不同,所以一个控件的数据更新不会影响到另一个控件的缓存数据。为了验证这一点,你可以创建一个包含可编辑的GridView控件的页面,其对应的ObjectDataSource控件启用缓存并使用ProductsBLL类的GetProducts()方法来获取数据。然后创建另一个页面或添加另一个GridView和ObjectDataSource控件,设置第二个ObjectDataSource控件调用GetProductsByCategoryID(categoryID)方法。由于这两个ObjectDataSource控件的SelectMethod属性不同,它们会有不同的缓存键值,因此在更新数据时可能会出现上述描述的情况。
如果您愿意接受一段时间内的旧缓存数据,可以选择使用时间基础的缓存过期策略(time-based expiries),设置适当的缓存时间长度。如果您对数据实时性要求极高,可能需要考虑缩短缓存时间或使用SQL缓存依赖项(SQL cache dependencies)。这些依赖项可以看作是您缓存的数据库数据的“通知”,当数据库中的数据发生变化时,它们会通知缓存系统进行更新。我们将在后续SQL缓存依赖项的细节。作者Scott Mitchell为我们带来了一系列关于ASP.NET的教程,其中深入了ObjectDataSource控件的缓存机制。该控件具有两个关键属性:CacheDuration和CacheExpirationPolicy,它们共同决定了缓存的时间和类型。CacheKeyDependency属性使得ObjectDataSource的缓存实体可以与现有的缓存从属体相互关联,通常这些关联与SQL缓存依赖有关。
ObjectDataSource控件虽然只是简单地进行数据缓存,但其内建功能可以通过编程实现。在表现层实现这一功能并无太大意义,因为ObjectDataSource控件已经提供了这一特性。尽管如此,我们仍可以在体系结构的其它层次实现缓存功能。为了达成这一目标,我们需要一个逻辑,这个逻辑应与ObjectDataSource调用的逻辑相同。
下一篇文章,我们将深入如何在体系结构的内部通过编程处理数据缓存。在这之前,让我们先理解ObjectDataSource的缓存机制,以便更好地在体系结构的其它部分实现自定义的缓存逻辑。
Scott Mitchell是这一系列教程的作者,他著有六本ASP/ASP.NET方面的书籍,是4GuysFromRolla.的创始人。自1998年以来,他一直致力于应用微软Web技术。他的教程对ASP.NET学习者来说,具有很高的参考价值。
缓存机制在Web应用程序中扮演着至关重要的角色,它可以显著提高性能并减少服务器负载。通过深入了解ObjectDataSource控件的缓存属性,我们可以更好地利用这些属性在ASP.NET应用程序中实现高效的缓存策略。我们还可以在其他体系结构的层次上实现自定义的缓存逻辑,以满足特定的需求。
无论是新手还是经验丰富的开发者,都可以通过学习和实践这些教程,提高他们在ASP.NET领域的技能。让我们一起享受编程的快乐吧!
平面设计师
- 在ASP.NET 2.0中操作数据之五十六:使用ObjectDataS
- php中随机函数mt_rand()与rand()性能对比分析
- ThinkPHP使用getlist方法实现数据搜索功能示例
- ibatis简单实现与配置
- jquery validation验证表单插件
- 郭刚堂直播认亲现场回顾:家庭团聚的感人瞬间
- 机箱电源线
- PHP设计模式之原型设计模式原理与用法分析
- PHP实现Snowflake生成分布式唯一ID的方法示例
- easyUI实现类似搜索框关键词自动提示功能示例代
- JavaScript贪吃蛇小组件实例代码
- 在ASP.NET 2.0中操作数据之四十三:DataList和Repeat
- vue-hook-form使用详解
- sql脚本查询数据库表,数据,结构,约束等操作的方
- javascript判断回文数详解及实现代码
- 完美实现八种js焦点轮播图(下篇)