您的位置:首页 > 其它

关于NHibernate中存在于Session中实例的3种状态的简单分析

2014-06-10 20:17 351 查看
在使用NHibernate的时候,在Session中会有3种状态。

1. 瞬时状态 (Transient)

由 new 命令开辟内存空间的对象,也就是平时所熟悉的普通对象。如: Student stu = new Student(); 瞬时对象特点:(1) 不和 Session 实例关联, 也就是说,在Session中没有缓存指向这个对象地址的引用; (2) 在数据库中没有和瞬时对象关联的记录,也就是说,这个对象的主键属性,在数据库中没有哪一行的主键与其对应。

2. 持久状态 (Persistent)

持久对象总是与 Session 和 Transaction 相关联,在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而必须在Transaction 终止,也就是执行 commit() 之后,才在数据库中真正运行 SQL 进行变更,持久对象的状态才会与数据库进行同步。在同步之前的持久对象称为脏 (dirty) 对象。瞬时对象转为持久对象:(1) 通过 Session 的 save() 和 saveOrUpdate()
方法把一个瞬时对象与数据库相关联,这个瞬时对象就成为持久化对象。(2) 使用 fine(),get(),load() 和 iterater() 方法查询到的数据对象,将成为持久化对象。持久化对象的特点:(1) 和 Session 实例关联,并且在Session中有指向这个内存对象地址的引用 (2) 在数据库中有和持久对象关联的记录。

3. 脱管状态 (Detached)

与持久对象关联的 Session 被关闭后,对象就变为脱管对象。对脱管对象的引用依然有效,对象可继续被修改。脱管对象特点:(1) 本质上和瞬时对象相同, 只是比瞬时对象多了一个数据库记录标识值 id. 注意这是数据库自增主键的情况。如果是assgin id情况,那么与瞬时对象可能就完全一样了。(2) 在数据库中有与其对应的记录。持久对象转为脱管对象:当执行 close() 或 clear(),evict() 之后,持久对象会变为脱管对象。瞬时对象转为持久对象:通过 Session 的 update(),saveOrUpdate()
和 lock() 等方法,把脱管对象变为持久对象。

最终总结起来,就是要分析session缓存中的id,referrence键值对是否志向指定对象的问题。transient不指向,persistent指向,detached不指向,但与ransient不同的是,数据库中已经有了对象对应的记录。

关于Session一些方法的运行原理。

Session.save(user):1, 把User对象加入Session缓存中,使它变成持久化对象。此时并没有数据库中对应的记录,清理缓存后,把SQL语句同步到数据库。2. 选用映射文件指定的标识生成ID;3,在Session清理缓存时候执行:在底层生成一个insert sql语句,把对象存入数据库。注意:在你执行Session.save(user)后,在Session清理缓存前,如果你修改user对象属性值,那么最终存入数据库的值将是最后修改的值;此过程中ID不能被修改;

 

Session.delete(user):如果user是持久化对象,则执行删除操作,同样底层数据库的执行条件是:在Session清理缓存时候;如果user是游离对象,将user对象和Session关联,使之成为持久化对象,所以这时候会发出select的SQL语句,这就是为什么你用NHibernate删除一个对象的时候,它会先发出select的语句。然后按照user 是持久化对象的过程执行。

Session.update(user):如果user是持久化对象,那么不进行任何操作,一切操作都是等到清空缓存的时候同步到数据库。如果user是游离对象,那么也是先转为持久对象,然后再等清理缓存的时候同步到数据库。所以Update的时候也会发出select语句。

Session.SaveOrUpdate(user):如果现在session中没有user的缓存,说明这是一个transient或者detached的对象,它会先向数据库发出select语句,注意select语句发出之前是会Flush缓存的,防止select到的是未更新的数据库内容。发出select语句后,如果没有查询到任何内容,说明这是一个新的对象,transient的,这时会把这个transient的对象放入到session缓存中,成为persistent状态。这是在session中标记一下这个对象对应的是什么样的SQL操作,在最终Flush拼接SQL语句的时候,是insert还是update. 如果查询到了记录,说明这是一个detached的对象,这时会把这个对象放入到session缓存中,变成persistent状态。最后,再调用session.Flush()的时候,会生成一些SQL语句,把这些内容同步到数据库中。如果现在session中有这个user对象所在地址的缓存,那么什么也不用做。Flush的时候同步到数据库即可。一种特别情况,如果session中没有这个对象的缓存,但是却有其他的某个对象缓存,有同一个id值存在,这是就会抛出异常。

Session 什么时候清理缓存,这是一个很关键的问题。什么是缓存清理?就是缓存中主键key对应的内存中的对象与数据库中同主键的记录进行同步的过程,也就是与数据库发生了交互,所有内存中对象的变动都提交到了数据库,注意,并不一定永久性的保持到数据库,这要看是否transaction的提交。并且,session缓存中的id与对象引用也清除。

清理缓存的时机如下,1,commit() 方法被调用时 2,查询时会主动commit清理缓存,保证查询结果能反映对象的最新状态。3,显示的调用session 的 flush方法。注意Session的commit()和flush()方法的区别,flush()方法进行清理缓存的操作,执行一系列的SQL语句,如果没有事务,则持久化到数据库。如果是事务,虽然在数据库中执行了SQL,但不会提交事务,是可以回滚的。commit()方法先调用flush(),然后提交事务。提交事务意味着对数据库所做的更新被永久保存下来。一般用法是Ssession.save(user);
Session.flush(); 当你调用save方法的时候,这个实体对象未必已经保存到数据库了,当你调用flush方法的时候是强制将对象保存到数据库。注意,强制保存到数据库的记录如果是在事务中的,也是可以回滚的。比如说,Flush之后,你去数据库select,会发现这条记录已经存在。但是由于某些原因造成事务回滚了,代码执行完后你再去select,会发现那条记录已经不再了,因为已经回滚到插入之前状态了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: