虽然很多帖子都是关于Spring的OpenSession / EntityManagerInViewFilter的主题写的,但我找不到任何提到它的缺陷。根据我的理解,并假设使用@Transactional服务层的典型分层Web应用程序架构,过滤器的工作方式如下:
在步骤8和9中,仍然管理由线程的EntityManager加载的对象。因此,如果在这些步骤中触及了惰性关联,则将使用仍然打开的EntityManager从数据库加载它们。据我所知,每次这样的访问都要求数据库打开一个事务。 Spring的事务管理将不会意识到这一点,因此我将其称为“隐式事务”。
我发现有两个问题:
一方面,这两个问题似乎足以拒绝使用此过滤器(性能损失,数据不一致)。另一方面,这个解决方案非常方便,避免编写几行代码,问题1可能不那么明显,问题2可能是纯粹的偏执狂。
您怎么看?
谢谢!
答案 0 :(得分:9)
正如您所说,OpenSessionInView过滤器在Web应用程序中非常方便。关于你提到的限制:
1)加载多个惰性关联将导致多个数据库事务,这可能会影响性能。
是的,进入数据库通常可能会导致性能问题。理想情况下,您希望在一次旅行中获取所需的所有数据。考虑使用Hibernate join-fetch。但是从DB中获取太多数据也会很慢。我使用的经验法则是每次绘制视图时都需要使用连接提取;如果在大多数情况下不需要数据,我会在需要时让Hibernate懒惰地获取它 - threadlocal open session会帮助它。
2)根对象及其惰性关联被加载到不同的数据库事务中,因此数据可能是陈旧的(例如,线程1加载根,线程2更新根关联,线程1加载根关联)。 / p>
想象一下在JDBC中编写这个应用程序 - 如果应用程序的一致性要求要求root和leaves都应该加载到同一个txn中,请使用join fetching。如果不是,通常就是这种情况,延迟抓取不会导致任何一致性问题。
恕我直言,OpenSessionInView更重要的缺点是你希望你的服务层在非网络环境中重用。根据您的描述,您似乎没有这个问题。
答案 1 :(得分:4)
我听到的反对OpenSessionInView和延迟加载的主要论点是过多的事务和对性能的负面影响。在使用率较低的应用程序上使用非常方便,但在大型应用程序中,我建议使用老式的完全填充的DTO(数据传输对象)。
答案 2 :(得分:4)
我遇到的OpenSessionInViewFilter的一个主要问题是使用AJAX应用程序和javascript。如果您使用javascript来呈现网格或某些UI组件;有一个懒惰的负载(考虑到你打开过滤器);并抛出异常。您的应用程序UI渲染需要折腾。数据可能永远不会显示,页面开始抛出奇怪的javascript异常,为此你需要编写额外的js代码来处理。而且您正在向用户公开db异常(不是一个好主意)。
在常规应用程序中,可以捕获这些异常并引发有效的用户异常。
答案 3 :(得分:1)
如果您的应用程序是多层体系结构(部署在不同JVM上的视图层,服务层将部署在不同的VM上),那么将会话保持在打开状态是没有意义的。如果您的服务层独立于您的应用层,我会看到不使用任何OpenSessionViewFilter。