在带有 jpa/hibernate 的 Spring 中,如何保持会话打开以避免延迟初始化异常?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1139985/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 03:54:19  来源:igfitidea点击:

In Spring with jpa/hibernate, how do I keep a session open to avoid lazy initialization exceptions?

hibernatespringjpalazy-loading

提问by HappyEngineer

I currently mark collections in entity beans as eager to avoid getting a lazy initialization exception when I try to access the collection properties after loading the bean with the EntityManager.

我目前将实体 bean 中的集合标记为渴望避免在使用 EntityManager 加载 bean 后尝试访问集合属性时出现延迟初始化异常。

If I instead leave the collection as lazy loading, how do I keep a session open? I thought about trying @Transactional, but even if that worked I wouldn't want to do it because it doesn't seem right to leave a transaction open over a long method.

如果我将集合保留为延迟加载,我如何保持会话打开?我想尝试使用@Transactional,但即使这样做有效,我也不想这样做,因为在很长的方法中打开事务似乎是不正确的。

采纳答案by lucas

https://www.hibernate.org/43.html

https://www.hibernate.org/43.html

Basically, you have a few options.

基本上,您有几个选择。

-You can use the "open session in view" pattern where you use a filter/interceptor/AOP - style logic to open a session when server side logic begins, and close it when it's through.

- 您可以使用“在视图中打开会话”模式,其中使用过滤器/拦截器/AOP 样式逻辑在服务器端逻辑开始时打开会话,并在会话结束时关闭它。

-You could implement conversations spanning several request-response cycles.

- 您可以实现跨越多个请求-响应周期的对话。

A plain old Servlet Filter is the easiest.

一个普通的旧 Servlet 过滤器是最简单的。

回答by JARC

One final option which seems to of been missed is you can build your object graph based on your use-case by using a JOIN.

最后一个似乎被遗漏的选项是您可以使用 JOIN 根据您的用例构建您的对象图。

This will result in the object being initialized, i.e the will not be a proxy.

这将导致对象被初始化,即不会是代理。

Use this approach if you are in control of the client (i.e you not creating open service publishing an api) because you need to know what state is being touched when the session is closed because the transaction has closed.

如果您控制客户端(即您没有创建发布 api 的开放服务),请使用这种方法,因为您需要知道当会话关闭时正在触摸什么状态,因为事务已关闭。

回答by Gregory Mostizky

As others have said, you should read up on "open session in view" pattern, the basic idea of which is to have a hibernate session open for the full duration of processing http request. There are both hibernate specificand springsolutions - I used spring's before and it works fine.

正如其他人所说,您应该阅读“视图中打开会话”模式,其基本思想是在处理 http 请求的整个持续时间内打开休眠会话。有特定休眠的解决方案和spring解决方案 - 我之前使用过 spring 并且它工作正常。

In the question you mention that you don't want to have transaction open for a long time. For most of the people this is not an issue because each request is processed relatively quickly. However if in your case it is indeed impossible this pattern will not work for you. Can you elaborate on why you don't want the transactions kept open?

在您提到的问题中,您不想长时间打开交易。对于大多数人来说,这不是问题,因为每个请求的处理速度都相对较快。但是,如果在您的情况下确实不可能,则此模式对您不起作用。你能详细说明为什么你不希望交易保持开放吗?

回答by Rich Seller

Are you using Spring's HibernateTemplate? It will manage the session for you I believe. Alternatively if you are on Hibernate 3.0.1 or above, Spring should still be able to manage the session for you.

你在使用 Spring 的 HibernateTemplate 吗?我相信它会为您管理会议。或者,如果您使用的是 Hibernate 3.0.1 或更高版本,Spring 应该仍然能够为您管理会话。

There is a SpringSource blog entrythat describes how to set this up. I've included an extract below:

有一个 SpringSource博客条目描述了如何设置它。我在下面包含了一个摘录:

Since Hibernate 3.0.1 (and in the Java Persistence API from the moment it was first released) it became possible for Spring to manage the underlying resource without you having to go through any of the templates that are available for those technologies. This means that even if you are using the Hibernate API directly (for example through SessionFactory.getCurrentSession()), you will still be using a Spring-managed Hibernate Session. The same holds for an EntityManager obtained through a JPA EntityManagerFactory. This is another reason why you don't have to use Spring's HibernateTemplate anymore to get an integrated experience. [...]

The following is the XML that we'll use to assemble the application. As you can see, we're of course still using the Spring way of setting up Hibernate (using the LocalSessionFactoryBean).

从 Hibernate 3.0.1(以及从它第一次发布的那一刻起就在 Java Persistence API 中),Spring 可以管理底层资源,而无需通过任何可用于这些技术的模板。这意味着即使您直接使用 Hibernate API(例如通过 SessionFactory.getCurrentSession()),您仍将使用 Spring 管理的 Hibernate Session。对于通过 JPA EntityManagerFactory 获得的 EntityManager 也是如此。这是您不必再使用 Spring 的 HibernateTemplate 来获得集成体验的另一个原因。[...]

以下是我们将用于组装应用程序的 XML。如您所见,我们当然仍在使用 Spring 设置 Hibernate 的方式(使用 LocalSessionFactoryBean)。

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <!– the works –>
</bean>
<bean id="accountRepo" class="com.mycompany.HibernateAccountRepository">
  <constructor-arg ref="sessionFactory"/>
</bean>

Now, as I said before, because of a small change in Hibernate 3.0.1, Spring is able to manage the Hibernate session for you, without you having to go through the Hibernate session. The one thing that was missing was the exception translation. To also get that going, you only need to annotate the repository with the @Repository annotation (provided by Spring) and turn on exception translation using a post processor.

现在,正如我之前所说,由于 Hibernate 3.0.1 中的一个小变化,Spring 能够为您管理 Hibernate 会话,而无需您通过 Hibernate 会话。缺少的一件事是异常翻译。为了实现这一点,您只需要使用 @Repository 注释(由 Spring 提供)来注释存储库,并使用后处理器打开异常转换。

@Repository // from org.springframework.stereotype
public class HibernateAccountRepository implements AccountRepository {
    // see above for full impl…
}

回答by Jens Schauder

When you leave a session open that has read some data, you will leave that transaction open. Long running transactions aren't that big of a problem (although that might depend on your database) what really causes problems are locks hold for a long time, but these might only get created once you actually change data in the database. Again this depends on your database.

当您让一个已经读取了一些数据的会话保持打开状态时,您将使该事务保持打开状态。长时间运行的事务并不是什么大问题(尽管这可能取决于您的数据库)真正导致问题的是锁持有很长时间,但这些可能只有在您实际更改数据库中的数据后才会创建。同样,这取决于您的数据库。

回答by Nelson

Now, I haven't used Spring, but I have used Hibernate in several different projects. The approach I settled on for the most recent project grew out of the Defensive Session Handlingpattern (in conjunction with a servlet filter), and we are happy with it. You can find more design patterns here.

现在,我没有使用过 Spring,但是我已经在几个不同的项目中使用过 Hibernate。我为最近的项目选择的方法源于防御性会​​话处理模式(结合 servlet 过滤器),我们对此很满意。您可以在此处找到更多设计模式。