您的位置:首页 > 其它

再说hibernate延迟加载问题

2009-12-18 14:06 597 查看
再说hibernate延迟加载问题
could not initialize proxy - no Session异常是session关闭引起的异常

解决hibernate延迟加载这里我们简单的说有几种:
1.把lazy设成false,最2的办法,但是最简单,简单就是美嘛,也依然会有很多再使用这个方式再解决类似问题。
2.在web.xml中加入
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
</filter
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>

3.HQL,用left join fetch或inner join fetch语法。
例如:from Item i left join fetch i.parentItem ii
可以在xml或annotion中配置。

4。利用拦截器实现或自己实现类似OpenSessionInViewFilter的功能。

5。用本地标准sql关联查询

6。用criteria查询。

具体实现自己去研究,这样方能进步。

再说说在业务逻辑层中使用延迟加载

即使在视图外面,Spring框架也通过使用AOP 拦截器 HibernateInterceptor来使得延迟加载变得很容易实现。这个Hibernate 拦截器透明地将调用配置在Spring应用程序上下文中的业务对象中方法的请求拦截下来,在调用方法之前打开一个Hibernate会话,然后在方法执行完之后将会话关闭。让我们来看一个简单的例子,假设我们有一个接口BussinessObject:

public interface BusinessObject {
public void doSomethingThatInvolvesDaos();
}
类BusinessObjectImpl实现了BusinessObject接口:

public class BusinessObjectImpl implements BusinessObject {
public void doSomethingThatInvolvesDaos() {
// lots of logic that calls
// DAO classes Which access
// data objects lazily
}
}

通过在Spring应用程序上下文中的一些配置,我们可以让将调用BusinessObject的方法拦截下来,再令它的方法支持延迟加载。看看下面的一个程序片段:

<beans>
<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl">
<property name="someDAO"><ref bean="someDAO"/></property>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="businessObjectTarget"/></property>
<property name="proxyInterfaces">
<value>com.acompany.BusinessObject</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>
</beans>

当 businessObject被调用的时候,HibernateInterceptor打开一个Hibernate会话,并将调用请求传递给 BusinessObjectImpl对象。当BusinessObjectImpl执行完成后,HibernateInterceptor透明地关闭了会话。应用层的代码不用了解任何持久层逻辑,还是实现了延迟加载。

在单元测试中测试延迟加载

最后,我们需要用J-Unit来测试我们的延迟加载程序。我们可以轻易地通过重写TestCase类中的setUp和tearDown方法来实现这个要求。我比较喜欢用这个方便的抽象类作为我所有测试类的基类。

public abstract class MyLazyTestCase extends TestCase {

private SessionFactory sessionFactory;
private Session session;

public void setUp() throws Exception {
super.setUp();
SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
session = SessionFactoryUtils.getSession(sessionFactory, true);
Session s = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));

}

protected Object getBean(String beanName) {
//Code to get objects from Spring application context
}

public void tearDown() throws Exception {
super.tearDown();
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
Session s = holder.getSession();
s.flush();
TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory);
}
}



我们首先说利用lazy=false来解决问题,这种方法是很好用,但是在实际的过程并不实用,
如果你某个对象关联好几个甚至十几个自对象,那么每次加载一个的话要执行很多HQL语句,
可想而知这个效率问题啦,特别是在使用列表的时候。所以不实用,而在上述所说的“在业务逻辑层中使用延迟加载”
也是这种情况吧。

很多使用WEB的朋友都喜欢利用openSessionView来加载这个问题。不错我也喜欢用,简单方便。但是说几种情况:

1.在quartz中总不能使用openSessionView模式吧 . (我就遇到过在quartz中用hibernate的延迟加载。openSessionView肯定不起作用了,所以要修改查询。
所以项目中用hibernate的延迟加载不是一个好注意,最后一次查出所有所需内容,有时侯效率更高。因为大部分项目中常常会用到一条记录相关联的另一表中的数据)

2.在spring后拦截的过程中,如果取拦截对象中的子对象利用openSessionView也不行

还有很多情况是不能用的,那么怎么解决呢。有人说那就lazy=False吧,你想在单纯的解决一个quartz的时候
调整整个WEB工程的加载好像不合适吧。

那怎么办呢,我觉得这个时候就可以考虑利用SQL语句使用这个重新加载一遍这个代理类,
这样在想调用的时候才手动加载比较合适和方便吧,但是估计要多几行代码,好好考虑
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: