我在Tomcat上使用Hibernate和Spring。我一直在阅读并重新阅读有关该主题的JBoss wiki page指向的内容,这很有帮助。但它给我留下了一些问题。
为每个请求启动事务的想法让我很烦恼。我想我可以将过滤器限制在某些控制器 - 可能将我需要交易的所有控制器放在伪“tx”路径下。但如果您不知道是否需要交易,那么使用交易不是一个坏主意吗?如果我只是在某些请求中进行读取 - 很可能来自缓存的读取 - 如果没有事务处理我不会更好吗?
我读过帖子,提到他们如何处理服务层的交易,我想用Spring做这件事。但那么过滤器代码是什么样的呢?我仍然希望在我的视图中可以使用会话进行一些延迟加载。
如果我只需要在我的过滤器中调用sessionFactory.getCurrentSession()
,它如何“释放”回会话工厂重新使用? (即使在使用事务时,我也希望看到session.close()
或其他内容。)谁在告诉会话工厂该会话可以重用?
也许是beginTransaction()
调用在请求期间将给定数据库连接绑定到给定会话?否则,会话根据需要从池中提取数据库连接,对吗?
感谢您对我的所有问题的耐心。
(如果你的答案将成为Spring文档的链接,你只会让我哭泣。你不想要那个,是吗?如果人们不再回答Spring,我会支付真钱 - 那样的相关问题。)
答案 0 :(得分:20)
您的疑虑是有效的,维基页面上提供的解决方案过于简单。不应在Web层管理事务 - 应在服务层处理。
正确的实现将打开一个会话并将其绑定到过滤器中的一个线程。没有开始交易。会话处于刷新模式从不 - 只读模式。服务呼叫会将会话设置为刷新模式auto&启动/提交事务。一旦服务方法完成,会话刷新模式将恢复为从不。
还有一个选项可以不在过滤器中打开会话。每个服务层调用将打开一个单独的会话& transaction - 在服务调用完成后,会话未关闭,但注册为延迟关闭。在Web请求处理完成后,会话将关闭。
Spring提供OpensessionInViewFilter,其工作原理如上所述。所以忽略jboss wiki文章,只需配置OpensessionInViewFilter - 一切都会好的。
SessionFactory.getCurrentSession() - 在内部创建会话并将其分配给本地线程。每个请求/线程都有自己的会话。 Web请求处理完成后,会话将关闭。在代码中,您只需要使用SessionFactory.getCurrentSession(),而不必关闭它。 jboss wiki页面上的代码示例是错误的 - 它应该在finally块中有一个SessionFactory.getCurrentSession()。close()。或者他们可能正在使用JTA事务并将hibernate配置为与JTA事务一起打开/关闭会话。
答案 1 :(得分:0)
如果过滤器为每个请求创建会话,则不会出现问题,因为会话来自会话池,并且它们将被重用。从操作系统的角度来看,没有任何反应。
事实上,hibernate会话是与数据库服务器的tcp(或套接字/管道)连接。 db conn创建的成本非常依赖于sql类型(postgresql在这方面特别糟糕,尽管它在任何事情上都非常好)。但它并不意味着什么,因为hibernate重用了数据库连接。
简单的hibernate过滤器解决方案也会在会话中为每个请求启动一个新事务。它是SQL视图中的事务:它是一个“BEGIN”和“COMMIT”查询。它总是很昂贵,而且应该减少。
恕我直言,如果只在当前请求的第一次查询时启动了交易,则可能的解决方案。也许春天有一些可用的东西。