在旨在运行作业的windows web服务的上下文中,我们尝试重用我们为web应用程序开发的NHibernate DAL。
对于会话管理,我们有两种选择,每种选择都有其优点和缺点:
有状态会话
- 随着它跟踪所有内容(L1/会话缓存),它将增长很多
- 需要小心关闭,会话处理似乎不足以清除一级缓存(我注意到使用内存探查器)
无状态会话
- 当前无法重用映射。所有用"lazy=true"声明的包最终都会出现以下异常(即使会话尚未关闭):
初始化[…]无法延迟初始化角色集合:[…],没有会话或会话关闭
显然,我们不能用lazy="false"来更新映射(它们与web应用程序共享),这将是性能的一个巨大缺点
- 无法与二级缓存交互:当部署共享二级缓存时,服务将无法使二级缓存数据无效,以便web应用程序拥有最新的数据
NHibernate已经被证明是很好的,直到现在,我们已经成功地在web上下文中使用了有状态会话和NHibernateLINQ,并使用了用于依赖注入的结构图。
我的问题是:
- 有什么好的解决方案可以在长时间运行的线程中使用NHibernate吗
- 我更喜欢使用有状态会话,但如何避免内存泄漏
问题解决了!实际上有几个问题。
第一个是关于实例的范围和多线程:
- 为每个线程创建一个新会话
- 线程完成工作后,立即清理所有附加到线程的实例。使用StructureMap,在线程中使用
new HybridLifecycle().FindCache().DisposeAndClear();
。它将导致连接到线程的会话关闭并进行处理 - 当生命周期是线程范围的时,StructureMap使用
ThreadStatic
变量来保持对对象缓存的引用。因此,诀窍是在线程中调用StructureMap的ObjectFactory。最初,在我们的应用程序中,一个主线程负责创建新线程,并调用ObjectFactory。这是我们犯的主要错误,而且一旦他们的工作完成,我们确实无法清理线程
会话类型:
- 只要小心地处理了实例化的StateFul会话,就不需要使用StateLessSession。在我们的案例中,StatelessSession有太多的缺点(缓存管理是主要的)
重要提示:请注意仅实例化一次NHibernate NHibernat会话工厂!
当仔细管理NHibernate实例时,不会出现内存泄漏。
在长时间运行的进程中保持有状态会话打开从来都不是一个好主意。
我的建议是重新设计您的流程,将与数据库相关的代码与非数据库相关的编码分离开来,这样任何与数据库有关的操作都可以在短时间内进行。