【问题标题】:Java Hibernate session and its scope?Java Hibernate 会话及其范围?
【发布时间】:2011-12-14 15:58:51
【问题描述】:

我刚刚开始使用 Hibernate 和 HSQLDB。在教程中,他们告诉我不要使用反模式“每次操作会话”。但是,每次我提交事务时,会话也会关闭。如果commit() 关闭会话,我应该如何避免使用getCurrentSession()

我有点好奇人们通常如何处理会议的范围。我已经看过几个关于构建 Web 应用程序的示例,其中每个请求都有一个会话。就我而言,我正在构建服务,并且不能应用相同的想法。该服务 24/7 全天候运行,偶尔会执行一些数据库操作。我应该一直保持数据库会话处于活动状态,并且只使用事务作为操作之间的边界(考虑到我的事务提交不会关闭会话的情况)还是应该为每个操作创建一个新的(这是反模式,但还能怎样?)。

提前致谢!

【问题讨论】:

  • 您是指守护进程意义上的“服务”,还是向外部消费者公开的“服务”,这些消费者只是以网络以外的方式进行交互?
  • 我的意思是守护进程意义上的“服务”,抱歉,应该澄清一下。

标签: java hibernate service


【解决方案1】:

该行为由正在使用的CurrentSessionContext 的实现决定。默认值恰好是ThreadLocalSessionContext,它会在提交时关闭,但您绝不会受到限制。

您可以使用ManagedSessionContext 配置/构建您喜欢的任何类型的会话范围,并在生命周期的适当开始和结束时绑定/取消绑定会话。将 Session 在入口处绑定到服务的工作单元并在出口处解除绑定,这对您来说似乎很有意义。 (为此构建健壮的代码当然不是一件容易的事。特别要记住,如果其中一种方法出现异常,您应该创建一个新的Session。)


回复评论变得太大而无法发表评论。

这是默认行为,因为它是唯一“安全”的东西,无需用户提供额外的工作或配置。如果您不帮忙,“提交”是 Hibernate 能够“看到”的唯一生命周期点,因此它必须在此处关闭,否则会话将面临永远悬空的风险。

确定潜在的会话生命周期边界需要对您实际在做什么有一定的了解。 “这是一项后台服务”并没有什么好说的。假设它会做一些事情,比如每 X 分钟空闲并醒来,做一些工作,然后再睡 X 分钟,那么这将是一个很好的边界来打开然后关闭会话。

在谈论“每个操作的会话”是一种反模式时,您可能使用了“操作”的过于宽泛的定义。

他们的意思是不要做类似的事情(对您的服务的虚构要求):

  1. 叫醒服务
  2. 打开会话
  3. 从数据库中读取文件位置
  4. 关闭会话
  5. 打开文件
  6. 打开会话
  7. 从当前文件状态更新数据库表
  8. 关闭会话
  9. 打开会话
  10. 将活动日志写入数据库
  11. 关闭会话
  12. 睡眠服务

在一个会话中执行此操作然后在最后关闭它是完全合理的。在单线程环境中,您自己在已知范围内管理所有内容,如果您愿意,您实际上可以自己打开和关闭会话,而无需使用currentSession。您只需要确保它在发生异常时关闭。如果您正在侦听操作系统事件,则事件处理将是会话的完美范围。

【讨论】:

  • 我明白了。如果那是反模式,为什么是默认的 ThreadLocalSessionContext?你的意思是我应该在我的服务启动时使用 getCurrentSession(),然后在关闭时关闭它?
  • 更新的答案,评论太长了
  • 感谢您的详尽解释!我更改为 ManagedSessionContext,但就我而言,这(到目前为止)几乎与将会话绑定到当前线程相同。如果我不这样做,我必须到处传递 Session 对象。稍后我可能会想出更好的设计...非常感谢您的意见!
  • 将会话扔到 ThreadLocal 中基本上是几乎每个人最终都会做的事情:) 这就是 OpenSessionInViewFilters 所做的一切。
猜你喜欢
  • 2019-01-04
  • 2011-08-21
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多