Nhibernate 之 一级缓存: Get(Id) 和 Load(Id)

来源:互联网 发布:centos pdo mysql 安装 编辑:程序博客网 时间:2024/06/07 15:13

适用版本: NHibernate 2.1.2-GA

hibernate.cfg.xml配置为:

(原文链接 http://ddbiz.com/?p=150)

    <property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>

 

NHibernate 的一级缓存(first level cache)是session级别的,随着session的close被清除掉。

session.Get和session.Load都是加载一个对象,但是他们有一定的区别:

 

session.Get<T>(id) 有几个特性:

1. 从数据库中加载对象,如果对象不存在,则返回null;

2. 被正确加载的对象,对象本身所有的属性都会连同对象被缓存在内存中;

3. 如果在同一个session中指定id的对象已经被加载过(即存在于一级缓存中),那么此对象将被从缓存中加载,而不再访问数据库

 

如下面的此时代码:

 

 

#1            Guid uid = new Guid("b36db9fd-34d6-441a-bf17-931f22658183");

#2            ISession s = SessionManager.Instance.GetSession();

#3            log.InfoFormat("Try Load User:{0}", uid);

#4            TUser u = s.Get<TUser>(uid);

#5            if (u == null) log.InfoFormat("User {0} not found", uid);

#6            else log.InfoFormat("User {0} loaded", uid);

#7

#8            log.InfoFormat("Try reload User: {0}", uid);

#9            TUser u2 = s.Get<TUser>(uid);

#10          if (u == null) log.InfoFormat("User {0} not found", uid);

#11          else log.InfoFormat("User {0} reloaded", uid);





#1 2010-07-20 15:34:46,343 INFO  mdi.opt.test - Try Get User:b36db9fd-34d6-441a-bf17-931f22658183

#2 2010-07-20 15:34:46,390 DEBUG NHibernate.SQL - SELECT tuser0_.Id as Id95_0_, tuser0_.Version as Version95_0_, tuser0_.UserType as UserType95_0_, tuser0_.Account as Account95_0_, ... FROM tuser tuser0_ WHERE tuser0_.Id=?p0;?p0 = b36db9fd-34d6-441a-bf17-931f22658183

#3 2010-07-20 15:34:46,468 INFO  mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183, Account=suvizhang loaded

#4 2010-07-20 15:34:46,468 INFO  mdi.opt.test - Try reGet User: b36db9fd-34d6-441a-bf17-931f22658183

#5 2010-07-20 15:34:46,468 INFO  mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183, Account=suvizhang reloaded

 

 

 

两次加载,只有一个sql语句从数据库中装载数据: #2; 第二次加载数据则直接返回了内存数据。

 

如果要加载的 Guid("b36db9fd-34d6-441a-bf17-931f22658183") 不存在与数据库中,那么Get<TUser>(uid)将返回null。

 

session.Load<T>(uid) 的特性

如果 <T>的 default lazy 为 true,

1.  session.Load<T>(uid) 返回一个 <T>Proxy对象

否则

2.  如果数据库中不存在此数据,则发生错误

 

3.  session.Load<T>(uid)同样要检测一级缓存,如果已经存在于缓存中,则直接返回数据。

 

其中2.和网络上讲的都不大一样,如果uid不存在与数据库,则同样返回的是一个 <T>proxy对象,只有在访问返回对象的具体属性时,才会发生错误,而不是在Load<T>的时候就发生错误。

 

如:

 


#1            Guid uid = new Guid("b36db9fd-34d6-441a-bf17-931f22658185");

#2            ISession s = SessionManager.Instance.GetSession();

#3            log.InfoFormat("Try Load User:{0}", uid);

#4            TUser u = s.Load<TUser>(uid);

#5            log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);

#6            log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);

#7

#8            log.InfoFormat("Try reload User: {0}", uid);

#9            TUser u2 = s.Load<TUser>(uid);


#10          log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);

#11          log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);

 

 

 

此例中, #1 代表的Guid在数据库中并不存在, #4返回的是一个 TUserproxy对象,此时并不发生错误;因为返回了一个代理对象,而该对象并不存在,所以#6中调用u.Account 是肯定会报错了。上例中的加载流程,可以从日志中发现:

 

 

 

#1 2010-07-20 16:47:06,421 INFO  mdi.opt.test - Try Load User:b36db9fd-34d6-441a-bf17-931f22658183

#2 2010-07-20 16:47:22,109 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - loading entity: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]

#3 2010-07-20 16:47:22,109 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - creating new proxy for entity

#4 2010-07-20 16:47:22,156 DEBUG NHibernate.AdoNet.ConnectionManager - after autocommit

#5 ......

#6 2010-07-20 16:47:22,296 INFO  NHibernate.Loader.Loader - SELECT tuser0_.Id as Id95_0_, tuser0_.Version as Version95_0_, tuser0_.UserType as UserType95_0_, tuser0_.Account as Account95_0_... FROM tuser tuser0_ WHERE tuser0_.Id=?p0

#7 2010-07-20 16:47:22,296 DEBUG NHibernate.SQL - SELECT tuser0_.Id as Id95_0_, tuser0_.Version as Version95_0_, tuser0_.UserType as UserType95_0_, tuser0_.Account as Account95_0_,... FROM tuser tuser0_ WHERE tuser0_.Id=?p0;?p0 = b36db9fd-34d6-441a-bf17-931f22658183

#8 2010-07-20 16:47:22,296 DEBUG NHibernate.Connection.DriverConnectionProvider - Obtaining IDbConnection from Driver

#9 2010-07-20 16:47:22,312 DEBUG NHibernate.AdoNet.AbstractBatcher - ExecuteReader took 4 ms

#10 2010-07-20 16:47:22,312 DEBUG NHibernate.AdoNet.AbstractBatcher - Opened IDataReader, open IDataReaders: 1

#11 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - processing result set

#12 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - result set row: 0

#13 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - result row: EntityKey[mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]

#14 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - Initializing object from DataReader: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]

#15 2010-07-20 16:47:22,328 DEBUG NHibernate.Persister.Entity.AbstractEntityPersister - Hydrating entity: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]

#16 2010-07-20 16:47:22,328 DEBUG NHibernate.Type.Int32Type - returning '1' as column: Version95_0_

#17 2010-07-20 16:47:22,328 DEBUG NHibernate.Type.PersistentEnumType - returning '0' as column: UserType95_0_

#18 2010-07-20 16:47:22,328 DEBUG NHibernate.Type.StringType - returning 'suvizhang' as column: Account95_0_

#19 ......

#20 2010-07-20 16:47:22,328 DEBUG NHibernate.Engine.TwoPhaseLoad - Version: 1

#21 2010-07-20 16:47:22,328 DEBUG NHibernate.Loader.Loader - done processing result set (1 rows)

#22 ......

#23 2010-07-20 16:47:22,359 DEBUG NHibernate.Loader.Loader - done entity load

#24 2010-07-20 16:47:44,531 INFO  mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183 loaded as TUserProxy

#25 2010-07-20 16:47:45,500 INFO  mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183, Account=suvizhang loaded

 

 

 

Load<T>(uid) 首先检查session的一级缓存,如果有此数据,则直接返回;如果缓存中没有此数据,则从数据库中加载数据,无论是否加载成功,都将返回一个TUserProxy(#24)对象;

 

 

针对第3点,测试如下:

#1            Guid uid = new Guid("b36db9fd-34d6-441a-bf17-931f22658183");

#2            ISession s = SessionManager.Instance.GetSession();

#3            log.InfoFormat("Try Load User:{0}", uid);

#4            TUser u = s.Get<TUser>(uid);

#5            log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);

#6            log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);

#7

#8            log.InfoFormat("Try reload User: {0}", uid);

#9            TUser u2 = s.Load<TUser>(uid);


#10          log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);

#11          log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);

 

#9 对已经在 #4装载过的数据,进行再次装载,log信息如下:

 

 

#1 2010-07-20 16:18:50,546 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - loading entity: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]

#2 2010-07-20 16:18:50,546 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - entity found in session cache

从#2中可以看到,此时Load<T>(uid)从一级缓存中装载了数据。
因为 session.Load<T>(uid)可以返回代理对象,这样对我们在处理对象间的关系时,就有很大帮助:我们可以装载关系对象的Id而不是装载整个关系对象(注:初次使用某个对象时-也就是session的一级缓存不存在该对象时,还是要从数据库中加载此对象)。

 

(原文链接 http://ddbiz.com/?p=150)

参考文章:

更详细的关于代理的介绍 http://www.cnblogs.com/RicCC/archive/2010/03/18/nhibernate-lazy-load.html