(N)Hibernate"每个应用程序会话"被认为是特定用例的邪恶?

chr*_*ris 8 java nhibernate orm hibernate transactions

好的,每个人都知道不鼓励使用(N)Hibernate的每个应用程序的全局会话.但是我有一个非常具体的,显然是非标准的用例,它似乎是理想的解决方案.

总而言之,我的(服务器)应用程序基本上将所有持久数据保持在内存中,并且从不查询数据库以进行正常操作.首先是数据库的唯一原因是数据在过程的生命周期中存活.我只想在应用程序启动时查询数据库以将所有内容提取到内存中.数据库实际上只有5-10 MB左右.

现在的问题是,如果我遵循会话必须短暂的建议,我必须为每个业务事务合并()我的所有数据或以某种方式手动跟踪所有更改,而不是利用NHibernate的自动更改跟踪.这使得持久性很难实现而不会导致很多性能开销.

所以我的问题是,为什么我不应该为这个特定的用例使用全局会话?

我所知道的反对全球会议的常见论点:

  1. 随着时间的推移,第一级缓存将被整个数据库填充=>我不介意,因为我实际上想要将所有数据都存储在内存中!

  2. 陈旧的数据和并发问题=>我的应用程序的设计使得所有可以访问或修改持久数据的代码必须是单线程的(有意的设计选择),并且它是唯一可以写入数据库的应用程序.所以这应该不是问题.

  3. 如果会引发异常(例如数据库超时)会话会被破坏=>这是我能看到的唯一真正的问题,但可以通过丢弃会话,创建新会话并刷新所有数据来解决.价格昂贵,但例外情况应该非常罕见,只能由主要错误或主要基础设施问题引起,这些问题都应该尽快解决.

所以我认为没有理由不为我的特定用例使用全局会话.或者有什么重要的东西我不见了?

更新1:这是一个服务器应用程序

更新2:这并不意味着长期存在的全球交易.交易仍然是短暂的 - 一个长期会话,许多短期交易.

Vla*_*cea 6

如果您将来自多个线程的所有事务扇入到单个专用后端线程执行程序中,那么您确实可以为每个应用程序使用单个会话.

锁定超时,服务器崩溃或约束违规可能会触发异常,因此撤消后备会话将导致丢弃所有第一级缓存条目,这对您的用例不利.在这种情况下,您将不得不从数据库重新获取所有内容,因为您使用单个后端线程,所有其他客户端线程将被阻止,这是不能令人信服的.

我建议您使用二级缓存.您可以将2LC提供程序配置为在内存中进行扩展,而不是溢出到磁盘.您可以在应用程序启动时加载二级缓存中的所有数据,并使用NONSTRICT_READ_WRITE缓存并发策略来加速写入(无论如何,并发问题对您来说都不是问题).

您还需要确保对集合使用2NL缓存.

最简单的设计是使用每个请求的会话,因为Session无论如何都是轻量级的,无论如何它都将从内存中的2LC获取数据.

您需要运行一些性能测试,以查看是否值得重用Session,而不是在每个事务上创建一个新的.您可能会发现此过程不是您的瓶颈,如果没有真正的证据,您不应该进行任何优化.

丢弃会话的另一个原因是大多数与数据库相关的异常无论如何都无法恢复.如果服务器关闭或当前请求引发约束违规,则重新安装它将无法解决任何问题.