NHibernate ISession Flush:何时何地使用它,为啥?
Posted
技术标签:
【中文标题】NHibernate ISession Flush:何时何地使用它,为啥?【英文标题】:NHibernate ISession Flush: Where and when to use it, and why?NHibernate ISession Flush:何时何地使用它,为什么? 【发布时间】:2010-09-07 18:49:00 【问题描述】:让我彻底困惑的一件事是 session.Flush
与 session.Commit
和 session.Close
结合使用。
有时session.Close
会起作用,例如,它会提交我需要的所有更改。我知道当我有一个事务或一个工作单元有多个创建/更新/删除时我需要使用提交,以便在发生错误时选择回滚。
但有时我真的被session.Flush
背后的逻辑所阻碍。我见过一些例子,你有一个session.SaveOrUpdate()
,然后是一个刷新,但是当我删除 Flush 时它仍然可以正常工作。有时我在 Flush 语句中遇到错误,说会话超时,删除它可以确保我没有遇到该错误。
是否有人对何时何地使用 Flush 有很好的指导?我已经为此查看了 NHibernate 文档,但我仍然找不到一个简单的答案。
【问题讨论】:
【参考方案1】:简单地说:
-
始终使用事务
不要使用
Close()
,而是将调用封装在ISession
中的using
语句中,或者在其他地方管理ISession 的生命周期。
来自the documentation:
来自
ISession
将不时执行将 ADO.NET 连接状态与内存中保存的对象状态同步所需的 SQL 语句。这个过程,flush,默认发生在以下几点Find()
或Enumerable()
的一些调用 来自NHibernate.ITransaction.Commit()
来自ISession.Flush()
SQL语句按以下顺序发出
所有实体插入,以相同的顺序使用
ISession.Save()
保存相应的对象 所有实体更新 所有集合删除 所有集合元素的删除、更新和插入 所有集合插入 所有实体删除,使用ISession.Delete()
删除相应对象的顺序相同(一个例外是使用原生 ID 生成的对象在保存时被插入。)
除非您明确指出
Flush()
,否则绝对不能保证 Session 何时执行 ADO.NET 调用,只能保证它们的执行顺序。然而,NHibernate 确实保证ISession.Find(..)
方法永远不会返回过时的数据;他们也不会返回错误的数据。可以更改默认行为以减少刷新频率。
FlushMode
类定义了三种不同的模式:仅在提交时刷新(并且仅在使用 NHibernateITransaction
API 时),使用解释的例程自动刷新,或者除非显式调用Flush()
,否则从不刷新。最后一种模式对于长时间运行的工作单元很有用,其中ISession
长时间保持打开和断开连接。
...
另请参考this section:
结束会话涉及四个不同的阶段:
刷新会话 提交事务 关闭会话 处理异常刷新会话
如果您恰好使用
ITransaction
API,则无需担心这一步。它会在事务提交时隐式执行。否则,您应该调用ISession.Flush()
以确保所有更改都与数据库同步。提交数据库事务
如果您使用的是 NHibernate ITransaction API,则如下所示:
tx.Commit(); // flush the session and commit the transaction
如果您自己管理 ADO.NET 事务,您应该手动
Commit()
ADO.NET 事务。sess.Flush(); currentTransaction.Commit();
如果您决定不提交更改:
tx.Rollback(); // rollback the transaction
或:
currentTransaction.Rollback();
如果你回滚事务,你应该立即关闭并丢弃当前会话,以确保 NHibernate 的内部状态是一致的。
关闭 ISession
对
ISession.Close()
的调用标志着会话的结束。 Close() 的主要含义是会话将放弃 ADO.NET 连接。tx.Commit(); sess.Close(); sess.Flush(); currentTransaction.Commit(); sess.Close();
如果您提供了自己的连接,
Close()
会返回对它的引用,因此您可以手动关闭它或将其返回到池中。否则Close()
将其返回到池中。
【讨论】:
对我来说,这一行很关键:“Close() 的主要含义是会话将放弃 ADO.NET 连接。”如果你不调用 ISession.Close(),你的连接会被填满,直到你得到 db 超时。 :o 我们通常:打开会话 session.BeginTransaction() 工作... session.Transaction.Commit() session.BeginTransaction() 工作... session.Transaction.Commit() session.BeginTransaction()工作.. session.Transaction.Commit() 处理会话。 精彩的文章和 +1 等 - 但是我认为可能需要进行编辑,因为您在顶部说“从不使用关闭”,然后是“如果您回滚事务,您应该立即关闭并丢弃当前会话” SQL语句的顺序可以改变吗?我的意思是我需要对实体对象执行更新而不是插入,因为我在相应的表中有一个约束。【参考方案2】:从 NHibernate 2.0 开始,DB 操作需要事务。因此,ITransaction.Commit()
调用将处理任何必要的刷新。如果由于某种原因您没有使用 NHibernate 事务,则不会自动刷新会话。
【讨论】:
【参考方案3】:ISession 将不时执行同步 ADO.NET 连接状态与内存中对象状态所需的 SQL 语句。
并且总是使用
using (var transaction = session.BeginTransaction())
transaction.Commit();
在提交更改之后,我们使用 transaction.Commit(); 将更改保存到数据库中;
【讨论】:
【参考方案4】:这是我的代码的两个示例,如果没有 session.Flush(),它将失败:
http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html
在此结束时,您可以看到一段代码,其中我设置了身份插入,保存实体然后刷新,然后设置身份插入关闭。如果没有这个刷新,它似乎是在打开和关闭身份插入,然后保存实体。
使用 Flush() 让我可以更好地控制正在发生的事情。
这是另一个例子:
Sending NServiceBus message inside TransactionScope
我不完全理解为什么会这样,但是 Flush() 阻止了我的错误发生。
【讨论】:
以上是关于NHibernate ISession Flush:何时何地使用它,为啥?的主要内容,如果未能解决你的问题,请参考以下文章
当 CacheMode=Ignore 时,为啥 NHibernate.ISession.CreateQuery 会返回与 CreateSQLQuery 不同的东西?
如何让 NHibernate ISession 缓存主键未检索到的实体
会话已关闭对象名称:'ISession'。在 NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - 如何阻止会话过早关闭