13

我在 Tomcat 上使用 Hibernate 和 Spring。我一直在阅读和重新阅读经常指向该主题的JBoss wiki 页面,这很有帮助。但这给我留下了一些问题。

  1. 为每个请求启动事务的想法让我很困扰。我想我可以将过滤器限制为某些控制器——也许将我所有需要事务的控制器放在伪“tx”路径或其他东西下。但是,如果您不知道是否需要交易,那么使用交易不是一个坏主意吗?如果我只是在一些请求中进行读取——很可能来自缓存的读取——没有事务我不是更好吗?

  2. 我已经阅读了提到他们如何在服务层处理事务的帖子,我想用 Spring 来做这件事。但是过滤器代码是什么样的呢?我仍然希望会话在我的视图中可用以进行一些延迟加载。

  3. 如果我所要做的就是调用sessionFactory.getCurrentSession()我的过滤器,它如何“释放”回会话工厂以供重用?(即使在使用事务时,我也希望看到 asession.close()或其他东西。)谁告诉会话工厂该会话可以重用?

  4. 也许是beginTransaction()在请求期间将给定数据库连接绑定到给定会话的调用?否则,会话会根据需要从池中提取数据库连接,对吗?

感谢您对我所有问题的耐心等待。

(如果你的答案是指向 Spring 文档的链接,那你只会让我哭泣。你不希望这样,是吗?如果人们不再回答与 Spring 相关的问题,我会付真金白银的。方式。)

4

2 回答 2

22

您的担忧是有效的,wiki 页面上提供的解决方案过于简单。事务不应该在 Web 层进行管理 - 它应该在服务层进行处理。

正确的实现会打开一个会话并将其绑定到过滤器中的一个线程。没有交易开始。会话被置于刷新模式从不 - 只读模式。服务调用会将会话设置为自动刷新模式并启动/提交事务。一旦服务方法完成,会话刷新模式将恢复为从不。

还有一个选项可以不打开过滤器中的会话。每个服务层调用都会打开一个单独的会话和事务 - 服务调用完成后,会话不会关闭,而是注册为延迟关闭。Web 请求处理完成后,会话将关闭。

Spring 提供了OpensessionInViewFilter,其工作方式如上所述。所以忽略 jboss wiki 文章,只配置 OpensessionInViewFilter - 一切都会好起来的。

SessionFactory.getCurrentSession() - 在内部创建会话并将其分配给本地线程。每个请求/线程都有自己的会话。Web 请求处理完成后,会话将关闭。在您的代码中,您只需要使用 SessionFactory.getCurrentSession() 而不必关闭它。jboss wiki 页面上的代码示例是错误的——它应该在 finally 块中有一个 SessionFactory.getCurrentSession().close()。或者他们可能正在使用 JTA 事务并将休眠配置为与 JTA 事务一起打开/关闭会话。

于 2012-05-19T11:31:43.013 回答
0

如果过滤器为每个请求创建一个会话,这不是问题,因为会话来自会话池,它们将被重用。从操作系统的角度来看,什么都没有发生。

事实上,休眠会话是与数据库服务器的 tcp(或套接字/管道)连接。创建 db conn 的成本很大程度上取决于 sql 类型(postgresql 在这方面非常糟糕,尽管它在任何方面都非常好)。但这并不意味着什么,因为hibernate重用了数据库连接。

简单的休眠过滤器解决方案也会为每个请求在会话上启动一个新事务。从 SQL 的角度来看,它是事务:它是一个“BEGIN”和“COMMIT”查询。它总是很昂贵,应该减少。

恕我直言,一个可能的解决方案是,如果事务仅在当前请求的第一个查询中启动。也许春天有一些有用的东西。

于 2013-01-16T00:32:26.083 回答