hibernate 延迟加载 数据调用

我在做一个小的项目,锻炼一下自己。请问一下我用的是struts+hibernate,其中有的team(班级)和Student多对一的关系,team对班级设置的是延迟加载,当我在页面中调用team.getStudents()的时候提示session was closed,但是我用不想把student设置为立即加载,有什么办法能使调用team.getStudents()方法时打开session?
[b]问题补充:[/b]
谢谢以上两位的回答,我现在还想问一下,我想让原来的项目保持struts+hibernate保持不变想要实现对students的延迟调用是使用OpenSessionInView 好呢还是自己做一个filter好呢,那个更方便,具体的做法是怎样的?这是我帮别人做得网站,很急,希望高手们能帮一下,谢了!
[b]问题补充:[/b]
如果使用OpenSessionInView 该引入哪些jar包?我感觉这个问题是hibernate很大的一个缺陷啊,为什么hibernate自己不做一个jar包解决呢,而使用spring的,这样很麻烦那

给你粘出几个类的代码,你自己看看,
类HibernateUtil.java,用这个类来管理session和事务
[code="java"]
import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import org.hibernate.exceptions.InfrastructureException;
import org.apache.commons.logging.*;

import javax.naming.*;

/**

  • Basic Hibernate helper class, handles SessionFactory, Session and Transaction.
  • Uses a static initializer for the initial SessionFactory creation
  • and holds Session and Transactions in thread local variables. All
  • exceptions are wrapped in an unchecked InfrastructureException. *
  • @author christian@hibernate.org
    */
    public class HibernateUtil {

    private static Log log = LogFactory.getLog(HibernateUtil.class);

    private static Configuration configuration;
    private static SessionFactory sessionFactory;
    private static final ThreadLocal threadSession = new ThreadLocal();
    private static final ThreadLocal threadTransaction = new ThreadLocal();
    private static final ThreadLocal threadInterceptor = new ThreadLocal();

    // Create the initial SessionFactory from the default configuration files
    static {
    try {
    configuration = new Configuration();
    sessionFactory = configuration.configure().buildSessionFactory();
    // We could also let Hibernate bind it to JNDI:
    // configuration.configure().buildSessionFactory()
    } catch (Throwable ex) {
    // We have to catch Throwable, otherwise we will miss
    // NoClassDefFoundError and other subclasses of Error
    log.error("Building SessionFactory failed.", ex);
    throw new ExceptionInInitializerError(ex);
    }
    }

    /**

    • Returns the SessionFactory used for this static class. *
    • @return SessionFactory / public static SessionFactory getSessionFactory() { / Instead of a static variable, use JNDI: SessionFactory sessions = null; try { Context ctx = new InitialContext(); String jndiName = "java:hibernate/HibernateFactory"; sessions = (SessionFactory)ctx.lookup(jndiName); } catch (NamingException ex) { throw new InfrastructureException(ex); } return sessions; */ return sessionFactory; }

    /**

    • Returns the original Hibernate configuration. *
    • @return Configuration */ public static Configuration getConfiguration() { return configuration; }

    /**

    • Rebuild the SessionFactory with the static Configuration. * */ public static void rebuildSessionFactory() throws InfrastructureException { synchronized(sessionFactory) { try { sessionFactory = getConfiguration().buildSessionFactory(); } catch (Exception ex) { throw new InfrastructureException(ex); } } }

    /**

    • Rebuild the SessionFactory with the given Hibernate Configuration. *
    • @param cfg */ public static void rebuildSessionFactory(Configuration cfg) throws InfrastructureException { synchronized(sessionFactory) { try { sessionFactory = cfg.buildSessionFactory(); configuration = cfg; } catch (Exception ex) { throw new InfrastructureException(ex); } } }

    /**

    • Retrieves the current Session local to the thread.
    • If no Session is open, opens a new Session for the running thread. *
    • @return Session */ public static Session getSession() throws InfrastructureException { Session s = (Session) threadSession.get(); try { if (s == null) { log.debug("Opening new Session for this thread."); if (getInterceptor() != null) { log.debug("Using interceptor: " + getInterceptor().getClass()); s = getSessionFactory().openSession(getInterceptor()); } else { s = getSessionFactory().openSession(); } threadSession.set(s); } } catch (HibernateException ex) { throw new InfrastructureException(ex); } return s; }

    /**

    • Closes the Session local to the thread. */ public static void closeSession() throws InfrastructureException { try { Session s = (Session) threadSession.get(); threadSession.set(null); if (s != null && s.isOpen()) { log.debug("Closing Session of this thread."); s.close(); } } catch (HibernateException ex) { throw new InfrastructureException(ex); } }

    /**

    • Start a new database transaction. */ public static void beginTransaction() throws InfrastructureException { Transaction tx = (Transaction) threadTransaction.get(); try { if (tx == null) { log.debug("Starting new database transaction in this thread."); tx = getSession().beginTransaction(); threadTransaction.set(tx); } } catch (HibernateException ex) { throw new InfrastructureException(ex); } }

    /**

    • Commit the database transaction. */ public static void commitTransaction() throws InfrastructureException { Transaction tx = (Transaction) threadTransaction.get(); try { if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) { log.debug("Committing database transaction of this thread."); tx.commit(); } threadTransaction.set(null); } catch (HibernateException ex) { rollbackTransaction(); throw new InfrastructureException(ex); } }

    /**

    • Commit the database transaction. */ public static void rollbackTransaction() throws InfrastructureException { Transaction tx = (Transaction) threadTransaction.get(); try { threadTransaction.set(null); if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) { log.debug("Tyring to rollback database transaction of this thread."); tx.rollback(); } } catch (HibernateException ex) { throw new InfrastructureException(ex); } finally { closeSession(); } }

    /**

    • Reconnects a Hibernate Session to the current Thread. *
    • @param session The Hibernate Session to be reconnected. */ public static void reconnect(Session session) throws InfrastructureException { try { session.reconnect(); threadSession.set(session); } catch (HibernateException ex) { throw new InfrastructureException(ex); } }

    /**

    • Disconnect and return Session from current Thread. *
    • @return Session the disconnected Session
      */
      public static Session disconnectSession()
      throws InfrastructureException {

      Session session = getSession();
      try {
      threadSession.set(null);
      if (session.isConnected() && session.isOpen())
      session.disconnect();
      } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
      }
      return session;
      }

    /**

    • Register a Hibernate interceptor with the current thread.
    • Every Session opened is opened with this interceptor after
    • registration. Has no effect if the current Session of the
    • thread is already open, effective on next close()/getSession(). */ public static void registerInterceptor(Interceptor interceptor) { threadInterceptor.set(interceptor); }

    private static Interceptor getInterceptor() {
    Interceptor interceptor =
    (Interceptor) threadInterceptor.get();
    return interceptor;
    }

}

[/code]

如果你用Spring的话,可以用OpenSessionInView

否则可以将session的生命期延长到整个请求域。
做法:先不忙关闭session,做一个Filter,响应请求后再关。

Filter类的doFilter()函数大致实现如下
其中HibernateSessionFactory是你的Hibernate会话工厂类名。
[code="java"]
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) {
chain.doFilter(request, response);
HibernateSessionFactory.closeSession();
}
[/code]

这个就要用到spring里面的OpenSessionInViewFilter,以保证session在页面上打开

借鉴spring的OpenSessionInViewFilter,看下它的代码改造成符合你应用环境的代码

不用引入什么包,spring的OpenSessionInViewFilter就是一个filter,你把spring源码里搞出来这个类放到你的web应用里,就当成是你自己写的一个filter嘛

引入spring可能要改的东西比较多,JE知识库里应该有不少spring的教程。

因为不知道你是否有写Hibernate工厂类,以下仅作参考
明白什么回事后很容易改

新建一个全局的过滤器
[code="java"]
package com.yourcomp;
import com.yourcomp.HibernateSessionFactory;
import javax.servlet.Filter;
//..各种import
public class HbnSessionFilter implements Filter{
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) {
try {
chain.doFilter(request, response);

HibernateSessionFactory.closeSession();

}
catch (Exception e) {
e.printStackTrace();
}
}
public void init(FilterConfig filterConfig) throws ServletException {}
public void destroy() {}
}
[/code]

web.xml中配置(望文生义,就不解释了……)
[code="xml"]

hbnSessionFilter
com.yourcomp.HbnSessionFilter


hbnSessionFilter
/*

[/code]

简单的filter类如下:
[code="java"]
import org.apache.commons.logging.*;

import javax.servlet.*;
import java.io.IOException;

/**

  • A servlet filter that opens and closes a Hibernate Session for each request.
  • This filter guarantees a sane state, committing any pending database
  • transaction once all other filters (and servlets) have executed. It also
  • guarantees that the Hibernate Session of the current thread will
  • be closed before the response is send to the client.
  • Use this filter for the session-per-request pattern and if you are
  • using Detached Objects. *
  • @see HibernateUtil
  • @author Christian Bauer christian@hibernate.org
    */
    public class HibernateFilter implements Filter {

    private static Log log = LogFactory.getLog(HibernateFilter.class);

    public void init(FilterConfig filterConfig) throws ServletException {
    log.info("Servlet filter init, now opening/closing a Session for each request.");
    }

    public void doFilter(ServletRequest request,
    ServletResponse response,
    FilterChain chain)
    throws IOException, ServletException {

    // There is actually no explicit "opening" of a Session, the
    // first call to HibernateUtil.beginTransaction() in control
    // logic (e.g. use case controller/event handler) will get
    // a fresh Session.
    try {
        chain.doFilter(request, response);
    
        // Commit any pending database transaction.
        HibernateUtil.commitTransaction();
    
    } finally {
    
        // No matter what happens, close the Session.
        HibernateUtil.closeSession();
    
    }
    

    }

    public void destroy() {}

}

[/code]

异常类InfrastructureException
[code="java"]
package org.hibernate.exceptions;

/**

  • This exception is used to mark (fatal) failures in infrastructure and system code. *
  • @author Christian Bauer christian@hibernate.org
    */
    public class InfrastructureException
    extends RuntimeException {

    public InfrastructureException() {
    }

    public InfrastructureException(String message) {
    super(message);
    }

    public InfrastructureException(String message, Throwable cause) {
    super(message, cause);
    }

    public InfrastructureException(Throwable cause) {
    super(cause);
    }
    }

[/code]

学习hibernate的时候参考网上的资料得来的,本人几乎没改给你的,

从spring源码里copy也是好主意,不过可能不太好理解。
[url]http://www.springsource.com/download/community?project=Spring%20Framework[/url]

你的方法效率好低,建议你把session放到线程中。也就是一个线程一个session。
这样你的问题可以解决。效率也快,你去gg看