2011-06-11 135 views
0

我有一个hibernate DAO,当试图访问一个包/集合的返回对象的成员时抛出一个“无法懒惰地初始化一个角色集合”异常。保持Hibernate会话通过注释失效? - 未能懒洋洋地初始化一个角色集合

我明白抛出异常的问题的范围。 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(); 

我将如何防止使用注解这个异常?我知道有一个解决办法是通过回调这伪代码可能看起来像延长Hibernate的Session:

@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(); 

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

回答

0

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

@OneToMany(mappedBy = "<something here>", cascade = CascadeType.ALL) 
@LazyCollection(LazyCollectionOption.FALSE) 
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会话是关闭的。

解决方案是在视图过滤器/拦截器中使用打开的会话。

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> 

希望它能帮助。

1

休眠会话与网络会话不同,它们不会过期。他们通过代码或基础设施手动关闭(例如Spring)。

在你的情况是不清楚你的会议是如何创建的第一个地方,因为如果你输入DAO没有会话,你会得到完全不同的例外(No Session Bound to Thread)。所以,不知怎的,你的会话被创建并关闭。我的猜测是你的DAO通过@Transactional或通过拦截器进行交易,所以会话在你输入时启动,当你退出DAO方法时会关闭。在这种情况下,只要将DAO上的事务传播设置为PROPAGATION_REQUIRED,就可以将@Transactional放在您的MVC方法上。

但请记住,除了通过@Transactional注释的方法之外,您不能携带您的收藏。例如,你不应该把它放在http会话中。如果这是一项要求,您可能需要考虑特殊的DTO对象来复制数据。

相关问题