在使用spring管理junit下的Hibernate时,会出现org.hibernate.LazyInitializationException: could not initialize proxy - no Session,原因大家都知道,当session关闭后,你访问对象中的延迟加载属性,都会报session已关闭的错误。解决办法一般有四种:
1、在关闭session之前,使用Hibernate.initialize(Object proxy)强制加载
2、在关闭session之前,对延迟属性进行一次get访问
3、使用hql预加载,一般会用到fetch语句
4、hbm映射文件中,让集合或对象属性的 lazy=false
以面四种方式,如果用在与spring整合后的hibernate中,方式1、方式2可能不太好合,除非你使用模板的execute回调,在项目中是如何解决的呢?采用openSessionInView过滤器,该过滤器非常有效,会保证在同一次请求中,打开一个session,在当次请求中,打开不会关闭(具体底 层实现用到了ThreadLocal类),请求结束后spring会妥善处理好session的。有了 openSessionInView,我们几乎看不到延迟加载错误了,但是,在开发中我们又遇到了另一个严峻的问题,我们在业务层的测试代码中,却无法开 启openSessionInView,这就出现了,在action及页面中都正常的代码,拿到junit测试中却无法通过,这该如何是好?解决办法如 下:
在你的测试类中的setUp和tearDown中,加上下面的代码,注意,要把sessionFactory定义到外面。
private SessionFactory sessionFactory;
public void setUp() throws Exception {
sessionFactory = (SessionFactory) beanFactory.getBean("sessionFactory");
Session s = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));
}
public void tearDown() throws Exception {
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
Session s = holder.getSession();
s.flush();
TransactionSynchronizationManager.unbindResource(sessionFactory);
}
上面的代码是纯junit下的测试,如果你用了AbstractTransactionalSpringContextTests作为测试基类,sessionFactory的初始化就没有这么复杂了,直接由spring注入进来即可。