0

我有一个休眠 DAO,它在尝试访问作为包/集合的返回对象的成员时抛出“无法延迟初始化角色集合”异常。

我了解引发异常的问题的范围。Hibernate 返回我的对象​​,对于任何集合,返回代理对象。在我的调用者中,当我去访问那些代理对象时,因为休眠会话已经过期,所以抛出了这个异常。

我想知道的是,如何使用注释来防止会话过期?是否可以?

例如,如果我的调用方法是:

@RequestMapping("refresh.url")
public ModelAndView refresh(HttpServletRequest request, HttpServletResponse response, int id) throws Exception {
    TestObject myObj = testObjDao.get(id);
    // throws the exception
    myObj.getCollection();

我将如何使用注释来防止这种异常?我知道一种解决方案是通过回调扩展休眠会话,在伪代码中可能类似于:

@RequestMapping("refresh.url")
public ModelAndView refresh(HttpServletRequest request, HttpServletResponse response, int id) throws Exception {
    session = get hibernate session...
    session.doInSession(new SessionCallback() {
        TestObject myObj = testObjDao.get(id);
        // no longer throws the exception
        myObj.getCollection();
    });

但这在我所有需要访问集合的函数中似乎相当重复。有没有办法简单地在上面打一个@Transactional注释并完成它?如:

@RequestMapping("refresh.url")
@Transactional  // this doesn't extend the session to this method?
public ModelAndView refresh(HttpServletRequest request, HttpServletResponse response, int id) throws Exception {
    TestObject myObj = testObjDao.get(id);
    // throws the exception
    myObj.getCollection();

感谢您帮助向我解释这一点。

4

3 回答 3

1

您需要执行以下操作:

1) 让 Spring 管理您的事务:

你可以在这里阅读更多信息: http ://www.mkyong.com/spring/spring-aop-transaction-management-in-hibernate/

和这里:

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction-declarative

2)现在延迟加载:

当您从 Hibernate 获取对象时,其所有惰性关联都作为代理返回,然后当您访问代理类时,您会收到异常,因为您的 Hibernate 会话已关闭。

解决方案是在 View Filter/Interceptor 中使用 open Session。

http://www.paulcodding.com/blog/2008/01/21/using-the-opensessioninviewinterceptor-for-spring-hibernate3/

它看起来就像这样:

<mvc:interceptors>
<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
</mvc:interceptors>

希望能帮助到你。

于 2011-06-11T15:17:27.190 回答
1

Hibernate 会话与 Web 会话不同,它们不会过期。它们通过您的代码或基础设施(例如 Spring)手动关闭。

在您的情况下,首先不清楚您的会话是如何创建的,因为如果您在没有会话的情况下进入 DAO,您将得到完全不同的异常 ( No Session Bound to Thread)。因此,您的会话以某种方式被创建和关闭。我的疯狂猜测是,您的 DAO 是@Transactional通过拦截器或通过拦截器进行事务处理的,因此当您进入会话时会启动会话,并在退出 DAO 方法时关闭会话。在这种情况下,@Transactional只要 DAO 上的事务传播设置为PROPAGATION_REQUIRED.

但请记住,您不能将您的收藏放在通过@Transactional. 例如,您不应该将其放在 http 会话中。如果这是一项要求,您可能需要考虑使用特殊的 DTO 对象来复制数据。

于 2011-06-12T05:22:30.220 回答
0

我使用的解决方案是在 DAO 中的集合上使用 @LazyCollection 注释。

@OneToMany(mappedBy = "<something here>", cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
于 2011-07-23T19:51:33.830 回答