再说hibernate延迟加载问题

再说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语句使用这个重新加载一遍这个代理类,
    这样在想调用的时候才手动加载比较合适和方便吧,但是估计要多几行代码,好好考虑

posted on 2017-07-10 14:39  alex5211314  阅读(137)  评论(0编辑  收藏  举报

导航