XPO:Session管理与缓存--机制篇
缓存的意义已经无需多言了。这里整理了一篇DevExpress的关于XPO的Session管理和缓存的文章:Session Management and Caching。
About Sessions
从6.1版开始,XPO新增了一个单独的Data Layer层,居于Session和IData Store之间,它的作用是接管之前版本中由Session管理的所有持久类的元数据。这样创建Session的资源开销被大大的减少,常常需要频繁创建新的Session实例的项目成为可能。
The Session as an Identity Map
Session包含了一个object cache,用以实现Identity Map。Identity Map在Martin Fowler的 "Patterns of Enterprise Application Architecture" 一书中有很好的解释(Summary)。
简单说来,它的任务是确保当相同的对象分别位于两个独立的查询的结果集里时,返回的应该是完全相同的同一个对象--不是任何的副本。即如下代码是应该可以通过的。
Person person2 = session.FindObject<Person>(new BinaryOperator("Name", "Billy Bott"));
Assert.AreSame(person1, person2);
注意:Session的object cache不是一个可选设置,不能被关闭。
Object cache的内部原理非常简单,每次有至数据库的查询时,XPO会检查相关对象的版本(使用Optimistic Locking字段)。若数据库中有更新版本的记录,则相关对象的数据会被更新至缓存并返回。否则即直接返回缓存中的数据而跳过重新创建相关对象等操作。
How current is the object cache?
“如何确保缓存中的数据足够新?”问题很简单,但是“足够新”在不同的项目中的含义是不同的。XPO提供如下的办法来处理这个问题:
- 创建新的Session来创建新的object cache。Session的生命周期越短,则其中的object cache中的内容也越新。并且这是通常推荐使用的唯一不会破坏缓存一致性(object cache consistency)的方法。
- 使用Optimistic Locking。XPO会自动处理。如下述代码所演示的:
using (Session session = new Session( )) {
new Person(session, "Billy Bott").Save( );
}
Session session1 = new Session( );
Session session2 = new Session( );
// Create a collection in session1 and check the content
XPCollection<Person> peopleSession1 = new XPCollection<Person>(session1);
Assert.AreEqual(1, peopleSession1.Count);
Assert.AreEqual("Billy Bott", peopleSession1[0].Name);
// Fetch the test object in session2 and make a change
Person billySession2 = session2.FindObject<Person>(new BinaryOperator("Name", "Billy Bott"));
billySession2.Name = "Billy's new name";
billySession2.Save( );
// Create a new collection in session1 - it will have the change from the other session
XPCollection<Person> newPeopleSession1 = new XPCollection<Person>(session1);
Assert.AreEqual(1, newPeopleSession1.Count);
Assert.AreEqual("Billy's new name", newPeopleSession1[0].Name);
// This last test shows the workings of the Identity Map - the object in the "old"
// collection has the same change, because it's actually the same object.
Assert.AreEqual("Billy's new name", peopleSession1[0].Name);
Assert.AreSame(peopleSession1[0], newPeopleSession1[0]);
- 还有一些其他的方法可供我们显式的从数据库里reload内容(或者至少看起来是这样--原文所述)。 Session.Reload(object)用以reload一个单一对象;XPBaseObject.Reload()通过调用Session的方法来reload它自己(等效于前一个方法?);该方法的另一个重载Session.Reload(object, forceAggregatesReload)在reload自己的同时可额外的reload所有相关联的属性;最后XPBaseCollection.Reload可reload一个Collection中的所有对象。
- 为避免破坏缓存一致性, Session.DropCache()方法可以用来一次性的抛弃掉所有object cache里的内容。注意这样将会使得所有之前通过该cache加载的对象都失效,所以在再次访问之前必须reload所有这些对象。这一般在多Session场合里只是一个备选方案,例如打算重用一个Session实例时。下述代码演示Collection Reloading:
using (Session session = new Session( )) {
new Person(session, "Billy Bott").Save( );
}
Session session1 = new Session( );
Session session2 = new Session( );
// Create a collection in session1 and check the content
XPCollection<Person> peopleSession1 = new XPCollection<Person>(session1);
Assert.AreEqual(1, peopleSession1.Count);
Assert.AreEqual("Billy Bott", peopleSession1[0].Name);
// Fetch the test object in session2 and make a change
Person billySession2 = session2.FindObject<Person>(new BinaryOperator("Name", "Billy Bott"));
billySession2.Name = "Billy's new name";
billySession2.Save( );
// The old session1 collection still has the old "version" of the object
Assert.AreEqual("Billy Bott", peopleSession1[0].Name);
// Now reload the session1 collection and check - the change will be there
peopleSession1.Reload();
Assert.AreEqual("Billy's new name", peopleSession1[0].Name);
当有选择性的reload数据时,需要留意的是它们的行为可能并不一定像我们所想的那样。实际上Session.Reload(...)重载是唯一在任何情况下都立刻从数据库中刷新所有对象的方法。而当我们reload一个Collection时,它只是在内部被标记为"not loaded"状态,而当程序下一次访问该Collection时,它才会如上述机制那样通过Optimistic Locking去走一次“常规的”数据加载流程。
Object Cache Consistency
缓存一致性。这个词在文章中已经出现多次,DX的原文对它做了较大篇幅的解释。简单说来,对于被缓存起来了的一批对象,他们个体的“新旧程度”不一定是最最重要的,很多时候,数据集来自于同一个时间片段,互相之间可以构成一个符合逻辑的意义的整体更为重要。
所以,作为一个object cache的实例,例如这里的Session实例,应该只包含一组逻辑上可以确保一致的数据。较好的实现方法则是“大方的”使用Session,每一个实例针对“一部分”的数据。(使用同一个Session做不同的工作可能会导致其object cache中的数据在逻辑上不一致,当选择性的reload数据时情况可能会更糟。)实际上这样也在一定程度上契合了上文中提到的“Session的生命周期越短,则其中的object cache中的内容也越新。并且这是通常推荐使用的唯一不会破坏缓存一致性(object cache consistency)的方法。 ”。
Variations
上文提到的缓存一致性和关系型数据里的隔离级别比较像,不同的是一个持久化对象的生命周期很可能要比一个事务要长久得多。XPO提供了一个参数用以改变当发现对象内容变动以后XPO的行为模式:
The flag is accessible as XpoDefault.OptimisticLockingReadBehavior (for the default value) and as Session.OptimisticLockingReadBehavior (for the session instance specific value) and it can have the following values:
Value | Description |
---|---|
Ignore | Changed objects are never reloaded. Best object cache consistency. |
ReloadObjects | Changed objects are automatically reloaded. |
ThrowException | When changed objects are encountered, a LockingException is thrown. |
Mixed | Outside of transactions, the behavior is ReloadObjects, inside transactions it's Ignore. |
The default value for this flag is currently "Mixed".
Data Layer Caching
除了上述Session里的object cache,XPO还提供了在数据级别缓存的功能。它将在数据库端执行的查询和相应的结果集缓存起来。该功能通过DataCacheRoot和DataCacheNode两个类实现。这两个类至少需要各一个,而当有特定需要时一个DataCacheRoot挂多个DataCacheNode也可以。数据实际上是缓存在DataCacheNode里的,DataCacheRoot负责全局的管理。
当一个已经执行过的查询被重复执行时,结果集将从缓存里直接返回而不再去数据库跑一遍。数据的新鲜程度可由MaxCacheLatency属性指定,它指定了缓存过期的最大TimeSpan。如果有多个DataCacheNode连接到一个DataCacheRoot,该DataCacheRoot亦负责更新所有包含了缓存数据的表。每次当DataCacheNode和DataCacheRoot通信时,DataCacheRoot都将更新信息推送给DataCacheNode。
下述代码演示了一个由1个DataCacheRoot和2个DataCacheNode组成的缓存结构。
InMemoryDataStore dataStore =
new InMemoryDataStore(new DataSet( ), AutoCreateOption.SchemaOnly);
DataCacheRoot cacheRoot = new DataCacheRoot(dataStore);
// Create two DataCacheNodes for the same DataCacheRoot
DataCacheNode cacheNode1 = new DataCacheNode(cacheRoot);
DataCacheNode cacheNode2 = new DataCacheNode(cacheRoot);
// Create two data layers and two sessions
SimpleDataLayer dataLayer1 = new SimpleDataLayer(cacheNode1);
SimpleDataLayer dataLayer2 = new SimpleDataLayer(cacheNode2);
Session session1 = new Session(dataLayer1);
Session session2 = new Session(dataLayer2);
// Create an object in session1
Person billySession1 = new Person(session1, "Billy Bott");
billySession1.Save( );
// Load and check that object in session2
XPCollection<Person> session2Collection = new XPCollection<Person>(session2);
Assert.AreEqual("Billy Bott", session2Collection[0].Name);
// Make a change to that object in session1
billySession1.Name = "Billy's new name";
billySession1.Save( );
// Reload the session2 collection. The DataCacheNode returns the result
// directly, so the change is not recognized. For the fun of it, do this
// several times. This whole block doesn't query the database at all.
for (int i = 0; i < 5; i++) {
session2Collection.Reload( );
Assert.AreEqual("Billy Bott", session2Collection[0].Name);
}
// Do something (anything) in session2. This makes the cacheNode2
// contact the cacheRoot and information about the updated data in
// the Person table is passed on to cacheNode2.
new DerivedPerson(session2).Save( );
// Reload the session2 collection again, and now the change is recognized.
// In this case, the query goes through to the database.
session2Collection.Reload( );
Assert.AreEqual("Billy's new name", session2Collection[0].Name);
在很多实际用途里,一般一个DataCacheNode就够了。代码可简化如下:
new DataCacheRoot(XpoDefault.GetConnectionProvider(
MSSqlConnectionProvider.GetConnectionString("server", "database"),
AutoCreateOption.DatabaseAndSchema))));
Optimistic Locking
Optimistic Locking也在上文中被提及多次。XPObject和XPCustomObject会自动加上这个INT型字段,它的主要功能是避免多个用户同时修改同一条记录。当需要在数据库中更新一条记录时,XPO首先检查这个字段,如果这条记录已经被更新了,则抛出一个错误。若都正常则XPO更新该记录,并且也步增一次Optimistic Locking字段。
可以通过把Session.LockingOption的值由默认的LockingOption.OptimisticLocking改为LockingOption.None来禁用Optimistic Locking。但这样不光会失去上述变更检测的功能,还会失去大部分的选择性reload功能。只剩XPBaseObject.Reload()和Session.DropCache()方法还能工作。
Common Usage Scenarios
ASP.NET Applications
这部分内容实际上在之前的文章“在ASP.NET项目中使用XPO的最佳准则”已经有详解,这里就不赘述了。
转载于:https://www.cnblogs.com/Elvin/archive/2010/02/08/1665565.html
XPO:Session管理与缓存--机制篇相关推荐
- XPO:Session管理与缓存--测试篇
之前整理了一下XPO在Session管理和缓存方面的一些资料(XPO:Session管理与缓存--机制篇),但原文的例程还是有些含糊的地方,这两天抽空做了一下测试.若有不当或者不对的地方敬请不吝赐教. ...
- 03MyBatis的事务管理和缓存机制
MyBatis的事务管理 事务的概念:事务是一个或几个操作组成的一个整体执行单元,它们要么全部执行,要么全不执行,不能只执行其中的某几个操作:可以理解为一个事务是一个程序中执行的最小单元. 事务的特性 ...
- Tomcat源码解析七:Tomcat Session管理机制
前面几篇我们分析了Tomcat的启动,关闭,请求处理的流程,tomcat的classloader机制,本篇将接着分析Tomcat的session管理方面的内容. 在开始之前,我们先来看一下总体上的结构 ...
- Picasso之图片缓存机制二ListView篇
前面已经个大家介绍Picasso图片缓存机制,大家不熟悉请看上一篇文章http://blog.csdn.net/qq_15950325/article/details/52809380,其实Picas ...
- kettle开发篇-缓存机制-Day7
前言: kettle 虽然作为较成熟稳定的数据处理工具,但也存在一些需要优化地方,如果没有深入了解kettle当出现类似产品问题的时候,可能会就束手无策了.今天就和大家聊聊kettle中缓存机制,和我 ...
- Spring 源码分析衍生篇十 :Last-Modified 缓存机制
文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...
- 设计一个移动应用的本地缓存机制
在手机应用程序开发中,为了降低与服务端的交互次数,加快用户的响应速度,一般都会在iOS设备中加一个缓存的机制,前面一篇文章介绍了iOS设备的内存缓存.这篇文章将设计一个本地缓存的机制. 功能需求 这个 ...
- WEB请求过程(http解析,浏览器缓存机制,域名解析,cdn分发)
WEB请求过程(http解析,浏览器缓存机制,域名解析,cdn分发) 目录 WEB请求过程(http解析,浏览器缓存机制,域名解析,cdn分发) 概述 HTTP解析 HTTP请求头 HTTP响应头 H ...
- 彻底吃透浏览器的缓存机制!
作者 | 浪里行舟 责编 | 胡巍巍 前言 缓存可以说是性能优化中简单高效的一种优化方式了.一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网 ...
最新文章
- UITextFIeld的输入格式问题 ----W.P
- Codeforces 1276C/1277F Beautiful Rectangle (构造)
- 页面闲置一段时间后,跳转
- python 面部识别_一文教你在Python中打造你自己专属的面部识别系统
- 镜像安装linux选择内核版本,在CentOS和Ubuntu中安装Linux Kernel 4.13.10
- Flink UI: Flink 1.10 如何查看 数据源 的背压(反压)情况(消费kafka)
- java连接虚拟机hadoop_本地eclipse java api连接远程虚拟机HBase
- 在线运行java代码并得到结果_Java代码是如何运行的?
- linux u盘读取速度,linux dd命令测试U盘读写速度
- java语言难度最大的地方_学习难度最高的五大编程语言
- 01-05.经典市场营销 Marketing公开课《科特勒营销管理》(一)
- runOnUiThread
- C++友元和友元函数
- 少年,暑期学编程可好?
- automagica 调用windows画图以及登录qq
- Data structure you've never heard of(枚举+dp)
- java如何解除文件锁定状态_如何使用Python解锁锁定的文件和文件夹(mac)
- Android 中的权限
- IP地址、主机名、域名解析(DNS)、虚拟机配置固定IP
- android 新闻应用、Xposed模块、酷炫的加载动画、下载模块、九宫格控件等源码
热门文章
- 【标日初级上册】第一单元知识点总结
- 新标日初级上册单词1----4
- 关于.net中的runat
- 运筹学与最优化matlab编程,运筹学与最优化MATLAB编程 教学课件 ppt 作者 吴祈宗 郑志勇 第8章.ppt...
- 脉脉互联网人才报告:名校毕业生首选字节跳动、腾讯、华为居前三
- 部署traefik2.2
- 关于参加计算机培训的通讯报道,通讯员积极参加新闻宣传培训班
- 使用vi、vim、sed、echo、cat操作文件
- 出来混,怎么能没有证券从业资格证!
- 使用poi-tl根据word模板生成word文件——解决生成的表格里数据行有小标题的这种需求