Java 带有@Transactional注释的Spring OpenSessionInViewFilter

Java 带有@Transactional注释的Spring OpenSessionInViewFilter,java,spring,hibernate,spring-transactions,Java,Spring,Hibernate,Spring Transactions,这是关于SpringOpenSessionInViewFilter在服务层与@Transactional注释一起使用的 我在这篇文章中读了很多关于堆栈溢出的文章,但仍然不知道是否应该使用OpenSessionInViewFilter来避免lazyiinitializationexception 如果有人能帮我找到以下问题的答案,那将是很大的帮助 在应用程序中使用OpenSessionInViewFilter是一种不好的做法吗 具有复杂的模式 使用此过滤器可能会导致N+1问题 如果我们使用的是O

这是关于Spring
OpenSessionInViewFilter
在服务层与
@Transactional
注释一起使用的

我在这篇文章中读了很多关于堆栈溢出的文章,但仍然不知道是否应该使用
OpenSessionInViewFilter
来避免
lazyiinitializationexception
如果有人能帮我找到以下问题的答案,那将是很大的帮助

  • 在应用程序中使用
    OpenSessionInViewFilter
    是一种不好的做法吗 具有复杂的模式
  • 使用此过滤器可能会导致
    N+1
    问题
  • 如果我们使用的是
    OpenSessionInViewFilter
    是否意味着
    @Transactional
    不是必需的
下面是我的Spring配置文件


类路径:hibernate.cfg.xml
org.hibernate.cfg.AnnotationConfiguration
${jdbc.dial}
真的

OpenSessionInView
是一个servlet过滤器,而不仅仅是打开一个hibernate会话并将其存储在为请求提供服务的线程的
SessionHolder
中。打开此会话后,当您在请求的呈现阶段使用此会话时,hibernate可以读取延迟初始化的集合和对象。调用
SessionFactory.getCurrentSession()
时可以访问此会话

但是,OpenSessionInView只是打开会话,并不开始任何事务。打开会话后,您可以从数据库中读取对象,但如果您想在事务中执行某些操作,则需要
@Transactional
注释或其他机制,以便在需要时区分事务的开始和结束

然后回答问题:

在具有复杂模式的应用程序中使用OpenSessionInViewFilter是否不好

如果您需要避免LazyInitializationException,并且重载只是打开新的Hibernate会话并在每个请求的请求结束时关闭它,那么这是一个很好的实践

使用此过滤器可能会导致N+1问题

我在许多项目中使用此过滤器,不会造成任何问题

如果我们使用OpenSessionInViewFilter,是否意味着不需要@Transactional

不可以。您只在线程的SessionHolder中打开了一个Hibernate会话,但是如果需要事务,您需要在此处插入my 0.02c(并继续扩展):

你不应该仅仅使用
OpenSessionInView
过滤器,因为你需要避开
lazyiinitializationexception
。这只会给你的系统增加另一层混乱和复杂性。您应该从系统设计中确切地知道需要在前端访问集合的位置。从这里开始,构建一个控制器方法来调用一个服务方法来检索您的集合就很容易而且(以我的经验来看)更符合逻辑

但是,如果您有另一个使用
OpenSessionInView
过滤器可以解决的问题,并且作为一个愉快的副作用,您可以打开一个会话,那么我不认为使用它访问您的集合有什么害处。但是,我要说的是,如果您使用
OpenSessionInView
在一个位置获取集合对象,那么您应该在其他位置重构代码以执行相同的操作,因为用于获取集合的策略在整个应用程序中是标准化的


将此重构的成本与编写控制器和服务方法的成本进行权衡,以确定您是否应该使用
OpenSessionInView
过滤器。

OpenSessionInViewFilter是一个servlet过滤器,它将hibernate会话绑定到http请求以及所有db操作(事务性和非事务性),相同的hibernate会话用于给定的http请求。这将db层暴露给web层,使其成为反模式

我的经验是,当我们希望对java对象进行更改而不希望这些更改反映在数据库中时,这使得代码很难调试。由于hibernate会话始终处于打开状态,因此它希望刷新数据库中的数据


只有当JS基本rest服务不在服务层之间时,才应使用此选项。

OpenSessionInViewFilter的典型使用模式是延迟加载某些实体,但在视图呈现阶段,视图需要该实体的某些属性,该属性最初未加载,因此需要获取此属性来自数据库的数据。现在,事务划分通常发生在web应用程序的服务层中,因此在视图呈现发生时,视图正在使用分离的实体,这导致在访问卸载的属性时出现
LazyInitializationException

从该url:

问题
典型web应用程序中的一个常见问题是在操作的主要逻辑完成后呈现视图,因此,Hibernate会话已经关闭,数据库事务已经结束。如果访问JSP(或任何其他视图呈现机制)内会话中加载的分离对象,则可能会遇到未加载的集合或未初始化的代理。您得到的异常是:LazyInitializationException:会话已关闭(或一条非常类似的消息)。当然,这是意料之中的,毕竟你已经结束了你的工作单元

第一种解决方案是打开另一个工作单元来渲染视图。这很容易做到,但通常不是正确的方法。渲染已完成动作的视图应该在第一个工作单元内部,而不是单独的工作单元。解决方案,在