为什么Spring的HibernateTemplate一般情况下不支持数据的惰性加载的源码分析

1.

                          
        HibernateTemplate template 
=  (MyHibernateTemplate) context.getBean( " hibernateTemplate " );
        Emp emp 
=  (Emp) template.load(Emp. class new  Long( 7369 ));
        
long  no  =  emp.getEmpno();
        log.info(
" empno =  "   +  no);
        String name 
=  emp.getEname();
        log.info(
" Empname =  "   +  name);

上面的代码在一般情况执行到String name=emp.getEname();的时候就会抛出org.hibernate.LazyInitializationException的异常,这个是容易理解的,因为Emp emp = (Emp) template.load(Emp.classnew Long(7369));默认是延迟数据的加载的,HibernateTemplate在执行完Emp emp = (Emp) template.load(Emp.classnew Long(7369));这句话后打开的session就关闭了。因而你在执行 String name = emp.getEname();这条语句时,这个时候才会向数据查询,但是这个时候session已经关闭,因而会出现上面的异常。为什么session会关闭呢?看一下Hibernate的源码就知道了,其核心代码是下面这段:

public  Object execute(HibernateCallback action,  boolean  exposeNativeSession)  throws  DataAccessException {
        Assert.notNull(action, 
" Callback object must not be null " );

        Session session 
=  getSession();
        
boolean existingTransaction =  SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
        
if  (existingTransaction) {
            logger.debug(
" Found thread-bound Session for HibernateTemplate " );
        }

        FlushMode previousFlushMode 
=   null ;
        
try  {
            previousFlushMode 
=  applyFlushMode(session, existingTransaction);
            enableFilters(session);
            Session sessionToExpose 
=  (exposeNativeSession  ?  session : createSessionProxy(session));
            Object result 
=  action.doInHibernate(sessionToExpose);
            flushIfNecessary(session, existingTransaction);
            
return  result;
        }
        
catch  (HibernateException ex) {
            
throw  convertHibernateAccessException(ex);
        }
        
catch  (SQLException ex) {
            
throw  convertJdbcAccessException(ex);
        }
        
catch  (RuntimeException ex) {
            
//  Callback code threw application exception...
             throw  ex;
        }
        
finally  {
            
if  (existingTransaction) {
                logger.debug(
" Not closing pre-bound Hibernate Session after HibernateTemplate " );
                disableFilters(session);
                
if  (previousFlushMode  !=   null ) {
                    session.setFlushMode(previousFlushMode);
                }
            }
            
else  {
                
//  Never use deferred close for an explicitly new Session.
                 if  (isAlwaysUseNewSession()) {
                    SessionFactoryUtils.closeSession(session);
                }
                
else  {
                    SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
                }
            }
        }
    }

因为HibernateTemplate是通过方法的回调执行你所操作的方法的。对应的话你调用的方法对应的就是

Object result = action.doInHibernate(sessionToExpose);这一句当这些代码执行完后,最后看finally语句,应该可以看到,如果existingTransaction这个变量为false,也就是说,你所进行的操作没有进行事务管理的,最总就关闭session了。大家可以代码跟踪一下就知道existingTransaction一般情况下的值就是为false的。那么我们就可以考虑让existingTransaction为true,也就是让自己的操作进入事务管理,这个时候session就不会关闭了,除非你自己关闭。比如我们进行一个junit测试如下:

package  jimmee.cn.edu.zju;

import  java.util.Iterator;
import  java.util.Set;

import  junit.framework.TestCase;

import  org.apache.log4j.Logger;
import  org.hibernate.Session;
import  org.hibernate.SessionFactory;
import  org.springframework.context.ApplicationContext;
import  org.springframework.context.support.ClassPathXmlApplicationContext;
import  org.springframework.orm.hibernate3.MyHibernateTemplate;
import  org.springframework.orm.hibernate3.MySessionFactoryUtils;
import  org.springframework.orm.hibernate3.SessionFactoryUtils;
import  org.springframework.orm.hibernate3.SessionHolder;
import  org.springframework.transaction.support.TransactionSynchronizationManager;

public   class  TestSession  extends  TestCase
{

    Logger log 
= Logger.getLogger(TestSession.class);
    SessionFactory sessionFactory 
= null;
    Session session 
= null;
    ApplicationContext bf 
= null;

    
public void testSession()
    
{

        MyHibernateTemplate template 
= (MyHibernateTemplate) bf
                .getBean(
"hibernateTemplate");
        Emp emp 
= (Emp) template.load(Emp.classnew Long(7369));
        
long no = emp.getEmpno();
        log.info(
"empno = " + no);
        String name 
= emp.getEname();
        log.info(
"Empname = " + name);
        
        Dept dept 
= (Dept) template.load(Dept.classnew Long(30));
        log.info(
"dept no =" + dept.getDeptno());
        log.info(
"dept name=" + dept.getDname());

        Set set 
= dept.getEmps();
        
for (Iterator iterator = set.iterator(); iterator.hasNext();)
        
{
            Emp emp3 
= (Emp) iterator.next();
            log.info(
"empname = " + emp3.getEname());
        }

    }


    @Override
    
protected void setUp() throws Exception
    
{
        
super.setUp();
        bf 
= new ClassPathXmlApplicationContext("applicationContext.xml");
        sessionFactory 
= (SessionFactory) bf.getBean("sessionFactory");
        session 
= MySessionFactoryUtils.getSession(sessionFactory, true);
        TransactionSynchronizationManager.bindResource(sessionFactory,
                
new SessionHolder(session));

    }


    @Override
    
protected void tearDown() throws Exception
    
{
        
super.tearDown();
        SessionHolder holder 
= (SessionHolder) TransactionSynchronizationManager
                .getResource(sessionFactory);
        Session s 
= holder.getSession();
        s.flush();
        TransactionSynchronizationManager.unbindResource(sessionFactory);
        MySessionFactoryUtils.closeSession(s);
        sessionFactory.close();

    }

}

 

为了明显的看到一些信息,我继承了HibernateTemplate了,在MyHibernateTemplate里重写了 public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException方法,自己添加了一些打印信息,最终输出结果如下:

2008-03-10 14:08:46,921 INFO [jimmee.cn.edu.zju.TestSession] - empno = 7369
Hibernate: select emp0_.EMPNO as EMPNO0_0_, emp0_.DEPTNO as DEPTNO0_0_, emp0_.ENAME as ENAME0_0_, emp0_.JOB as JOB0_0_, emp0_.MGR as MGR0_0_, emp0_.HIREDATE as HIREDATE0_0_, emp0_.SAL as SAL0_0_, emp0_.COMM as COMM0_0_ from SCOTT.EMP emp0_ where emp0_.EMPNO=?
2008-03-10 14:08:47,015 INFO [jimmee.cn.edu.zju.TestSession] - Empname = SMITH
2008-03-10 14:08:47,015 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@2bccb2] for key [org.hibernate.impl.SessionFactoryImpl@18bbf55] bound to thread [main]
2008-03-10 14:08:47,015 INFO [org.springframework.orm.hibernate3.MyHibernateTemplate] - session id=26578114
2008-03-10 14:08:47,015 INFO [org.springframework.orm.hibernate3.MyHibernateTemplate] - factory
id=org.hibernate.impl.SessionFactoryImpl@18bbf55
2008-03-10 14:08:47,015 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@2bccb2] for key [org.hibernate.impl.SessionFactoryImpl@18bbf55] bound to thread [main]
2008-03-10 14:08:47,015 INFO [org.springframework.orm.hibernate3.MyHibernateTemplate] - existingTransaction  = true
2008-03-10 14:08:47,015 DEBUG [org.springframework.orm.hibernate3.MyHibernateTemplate] - Found thread-bound Session for HibernateTemplate
2008-03-10 14:08:47,015 DEBUG [org.springframework.orm.hibernate3.MyHibernateTemplate] - Not closing pre-bound Hibernate Session after HibernateTemplate

2008-03-10 14:08:47,015 INFO [jimmee.cn.edu.zju.TestSession] - dept no =30
Hibernate: select dept0_.DEPTNO as DEPTNO1_0_, dept0_.DNAME as DNAME1_0_, dept0_.LOC as LOC1_0_ from SCOTT.DEPT dept0_ where dept0_.DEPTNO=?
2008-03-10 14:08:47,031 INFO [jimmee.cn.edu.zju.TestSession] - dept name=SALES
Hibernate: select emps0_.DEPTNO as DEPTNO1_, emps0_.EMPNO as EMPNO1_, emps0_.EMPNO as EMPNO0_0_, emps0_.DEPTNO as DEPTNO0_0_, emps0_.ENAME as ENAME0_0_, emps0_.JOB as JOB0_0_, emps0_.MGR as MGR0_0_, emps0_.HIREDATE as HIREDATE0_0_, emps0_.SAL as SAL0_0_, emps0_.COMM as COMM0_0_ from SCOTT.EMP emps0_ where emps0_.DEPTNO=?
2008-03-10 14:08:47,046 INFO [jimmee.cn.edu.zju.TestSession] - empname = BLAKE
2008-03-10 14:08:47,046 INFO [jimmee.cn.edu.zju.TestSession] - empname = WARD
2008-03-10 14:08:47,046 INFO [jimmee.cn.edu.zju.TestSession] - empname = TURNER
2008-03-10 14:08:47,046 INFO [jimmee.cn.edu.zju.TestSession] - empname = ALLEN
2008-03-10 14:08:47,046 INFO [jimmee.cn.edu.zju.TestSession] - empname = MARTIN
2008-03-10 14:08:47,046 INFO [jimmee.cn.edu.zju.TestSession] - empname = JAMES
2008-03-10 14:08:47,046 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@2bccb2] for key [org.hibernate.impl.SessionFactoryImpl@18bbf55] bound to thread [main]
2008-03-10 14:08:47,062 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] - Removed value [org.springframework.orm.hibernate3.SessionHolder@2bccb2] for key [org.hibernate.impl.SessionFactoryImpl@18bbf55] from thread [main]
2008-03-10 14:08:47,062 INFO [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closing Hibernate Session
2008-03-10 14:08:47,062 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closing Hibernate Session
2008-03-10 14:08:47,062 INFO [org.springframework.orm.hibernate3.SessionFactoryUtils] - session id=26578114
2008-03-10 14:08:47,078 INFO [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closed Hibernate Session
2008-03-10 14:08:47,078 INFO [org.hibernate.impl.SessionFactoryImpl] - closing

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值