网站首页 新闻首页 网页设计图形动画软件编程网站开发办公软件操作系统数据库网络技术认证考试范文资料黑客攻防 书籍教程 进入论坛

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

http://www.diybl.com/ 2008-3-11  网络 点击:  [ 评论 ]
文章搜索:    【点击打包该文章】

1.



                          
        HibernateTemplate template 
= (MyHibernateTemplate) context.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);

上面的代码在一般情况执行到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



欢迎光临DIY部落,点击这里查看更多文章教程   【点击打包该文章】
如果图片或页面不能正常显示请点击这里 站内搜索:   

文章评论

请您留言

 

最新新闻