我目前将实体 bean 中的集合标记为急于避免在使用 EntityManager 加载 bean 后尝试访问集合属性时出现延迟初始化异常。
如果我将集合保留为延迟加载,如何保持会话打开?我考虑过尝试@Transactional,但即使这有效,我也不想这样做,因为让事务在很长的方法上保持打开状态似乎是不正确的。
我目前将实体 bean 中的集合标记为急于避免在使用 EntityManager 加载 bean 后尝试访问集合属性时出现延迟初始化异常。
如果我将集合保留为延迟加载,如何保持会话打开?我考虑过尝试@Transactional,但即使这有效,我也不想这样做,因为让事务在很长的方法上保持打开状态似乎是不正确的。
https://www.hibernate.org/43.html
基本上,你有几个选择。
-您可以使用“在视图中打开会话”模式,其中使用过滤器/拦截器/AOP - 样式逻辑在服务器端逻辑开始时打开会话,并在结束时关闭它。
- 您可以实现跨越多个请求-响应周期的对话。
一个普通的旧 Servlet 过滤器是最简单的。
最后一个似乎被遗漏的选项是,您可以使用 JOIN 根据您的用例构建对象图。
这将导致对象被初始化,即不会成为代理。
如果您可以控制客户端(即您没有创建发布 API 的开放服务),请使用此方法,因为您需要知道由于事务已关闭而关闭会话时所触及的状态。
你在使用 Spring 的 HibernateTemplate 吗?我相信它会为你管理会议。或者,如果您使用的是 Hibernate 3.0.1 或更高版本,Spring 应该仍然能够为您管理会话。
有一个 SpringSource博客条目描述了如何设置它。我在下面包含了一个摘录:
从 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>
现在,正如我之前所说,由于 Hibernate 3.0.1 中的一个小改动,Spring 能够为您管理 Hibernate 会话,而无需您通过 Hibernate 会话。缺少的一件事是异常翻译。为了实现这一点,您只需要使用 @Repository 注释(由 Spring 提供)来注释存储库,并使用后处理器打开异常翻译。
@Repository // from org.springframework.stereotype
public class HibernateAccountRepository implements AccountRepository {
// see above for full impl…
}
当您打开已读取一些数据的会话时,您将打开该事务。长时间运行的事务并不是什么大问题(尽管这可能取决于您的数据库)真正导致问题的原因是锁持有很长时间,但这些可能只有在您实际更改数据库中的数据时才会创建。同样,这取决于您的数据库。