如何使NHibernate存储库线程安全

时间:2016-04-17 14:00:35

标签: c# multithreading nhibernate fluent-nhibernate

我有一个NHibernate存储库类,它在单个事务中对多个表执行一些READ操作。

但我有一段旧代码试图在Parallel Threads上调用这个NHibernate类,比如

someList.AsParallel().Select(x=>x.repo.GetData());

操作失败说 SQL不支持多个事务,如何使NHibernate线程中的ISession安全?

2 个答案:

答案 0 :(得分:4)

NHibernate ISession不是线程安全的,周期 来自NHibernate参考文档Chapter 1, Getting started section

  

ISession是一个非线程安全对象,表示数据库的单个工作单元。

您应该改变旧的代码。

无论如何,这段代码看起来像编码恐怖。它遭受n + 1加载不良做法。通常这种情况发生时,延迟加载未正确设置(忘记在实体和集合的映射中设置足够的batch-size,而没有设置default_batch_fetch_size配置参数)。但在那里,它是明确编码的!

在循环中调用DB是一种性能反模式,您应该先修复它。在AsParallel中调用它看起来只是原始开发人员尝试“优化”这种编码恐怖的不良尝试。

要修复它,您应该在一次调用中加载所有数据,然后根据需要将其分发到列表中。您可以先将数据投影到字典中,以避免使用O(n²)调度算法。

完成后,AsParallel应该已经消失,您的线程安全也会出现问题。

如果事情太复杂(比你的例子显示的更多),或者真的对应于需要用并行性完成的事情,那么你应该为每个ISession实例化一个专用的GetData在您的并行处理中。

答案 1 :(得分:1)

请注意,使用延迟加载和代理时,甚至实体都是线程安全的!

  • 如果要并行化查询,则需要在单独的事务中执行此操作。考虑隔离和原子性。如果需要在单个事务中,则需要以不同的方式提高性能。
  • 如果要对实体的计算进行并行化,则应在主线程中执行优化查询,将实体中的数据复制到DTO并在多个线程中处理它。不要从后台线程访问实体!