您的位置:首页 > 编程语言 > Java开发

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

2008-03-10 14:18 746 查看
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.class, new Long(7369));默认是延迟数据的加载的,HibernateTemplate在执行完Emp emp = (Emp) template.load(Emp.class, new 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.class, new Long(7369));


long no = emp.getEmpno();


log.info("empno = " + no);


String name = emp.getEname();


log.info("Empname = " + name);




Dept dept = (Dept) template.load(Dept.class, new 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: