session管理(一)

Session并非线程安全

共享变量session实现Session的重用,避免了每次操作都要重新创建,但是多个线程同时使用一个Session实例进行数据存取,则将会导致Session 数据存取逻辑混乱

  public class TestServlet extends HttpServlet {
   private Session session;
   public void doGet( HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
     session = getSession();
     doSomething();
     session.flush();
   }
   public void doSomething(){
  ......//基于session的存取操作
   }
  }

不安全解释,例如:Servlet 运行是多线程的,而应用服务器并不会为每个线程都创建一个Servlet实例,也就是说,TestServlet在应用服务器中只有一个实例(在Tomcat中是这样,其他的应用服务器可能有不同的实现),而这个实例会被许多个线程并发调用,doGet 方法也将被不同的线程反复调用,可想而知,每次调用doGet 方法,这个唯一的TestServlet 实例的session 变量都会被重置

Hibernate对session的管理

hibernate提供了getCurrentSession 和openSession()来获取session ,首先看看两个方法的区别
1 getCurrentSession创建的session会和绑定到当前线程,而openSession不会。
2 getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭
3.getCurrentSession本地事务(本地事务:jdbc)时 要在配置文件里进行如下设置
    * 如果使用的是本地事务(jdbc事务)
        <property name="hibernate.current_session_context_class">thread</property>
   * 如果使用的是全局事务(jta事务)
       <property name="hibernate.current_session_context_class">jta</property> 
 
 4.getCurrentSession () 总是使用当前的session,openSession()  则重新建立一个新的session 


在一个应用程序中,如果DAO 层使用Spring 的hibernate 模板,通过Spring 来控制session 的生命周期,则首选getCurrentSession ()。

用过Hibernate的人都知道Hibernate最原始的使用Session方式

获取SessionFactory

打开Session

打开事务(可选)

执行操作

关闭事务(可选)

关闭Session


getCurrentSession() 这个方法就是通过SessionContext来减少Session创建的。比如常用的ThreadLocalSessionContext:


Session current = existingSession( factory );  
if (current == null) {  
    current = buildOrObtainSession();  
    current.getTransaction().registerSynchronization( buildCleanupSynch() );  
    if ( needsWrapping( current ) ) {  
        current = wrap( current );  
    }  
    doBind( current, factory );  
}  
return current;  
currentSession()内部先从ThreadLocal中获取Session。若不为null直接返回,若为null则openSession(...)一个Session并把这个Session对象绑定在ThreadLocal上。它就是通过在ThreadLocal中注册绑定Session来确保线程中最多只有一个Session对象。



关于ThreadLocal

在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本

 public class ThreadLocal {   
      private Map values = Collections.synchronizedMap(new HashMap());   
      public Object get() {   
         Thread currentThread = Thread.currentThread();    
         Object result = values.get(currentThread);               //通过currentThread来找result  
         if(result == null&&!values.containsKey(currentThread)) {   
            result = initialValue();   
            values.put(currentThread, result);    
         }   
         return result;    
      }   
      public void set(Object newValue) {   
         values.put(Thread.currentThread(), newValue);   
      }   
      public Object initialValue() {   
         return null;    
      }   
 } 




Hibernate官方提供的一个ThreadLocal工具:


package cash.util;


import net.sf.hibernate.HibernateException;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Session;
import net.sf.hibernate.cfg.Configuration;


import org.apache.log4j.Logger;


/**
 * Helper Singleton class to manage Hibernate Sessions.
 *
 * @author Joel Hockey
 * @version $Id: HibernateUtil.java,v 1.24 2006/08/23 18:50:50 rainerh Exp $
 */
public class HibernateUtil {


    /** ThreadLocal Session Map */
    public static final ThreadLocal MAP = new ThreadLocal();


    private static final Logger LOG = Logger.getLogger(HibernateUtil.class);


    private static final SessionFactory SESSION_FACTORY;


    /** Make default construct private */
    private HibernateUtil() { }


    /** Loads Hibernate config. */
    static {
        try {
            LOG.debug("HibernateUtil.static - loading config");
            SESSION_FACTORY = new Configuration().configure().buildSessionFactory();
            LOG.debug("HibernateUtil.static - end");
        } catch (HibernateException ex) {
            throw new RuntimeException("Exception building SessionFactory: " + ex.getMessage(), ex);
        }
    }


    /**
     * Gets Hibernate Session for current thread.  When finished, users
     * must return session using {@link #closeSession() closeSession()} method.
     * @return Hibernate Session for current thread.
     * @throws HibernateException if there is an error opening a new session.
     */
    public static Session currentSession() throws HibernateException {
        Session s = (Session)MAP.get();
        // Open a new Session, if this Thread has none yet
        if (s == null) {
            s = SESSION_FACTORY.openSession();
            MAP.set(s);
        }
        return s;
    }


    /**
     * Closes the Hibernate Session.  Users must call this method after calling
     * {@link #currentSession() currentSession()}.
     * @throws HibernateException if session has problem closing.
     */
    public static void closeSession() throws HibernateException {
        Session s = (Session)MAP.get();
        MAP.set(null);
        if (s != null) {
            s.close();
        }
    }
}


针对WEB程序,还可以利用Servlet2.3的Filter机制,轻松实现线程生命周期内的Session管理。下面是一个通过Filter进行Session管理的典型案例:

public class PersistenceFilter implements Filter {  
  protected static ThreadLocal hibernateHolder = new ThreadLocal();  
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
    hibernateHolder.set(getSession());  
    try {  
        
      chain.doFilter(request, response);  
        
    } finally {  
      Session session = (Session) hibernateHolder.get();  
      if (session != null) {  
        hibernateHolder.set(null);  
        try {  
          session.close();  
        } catch (HibernateException ex) {  
          throw new ServletException(ex);  
        }  
      }  
    }  
  }  
    
}  

在3.0版本之前,使用Hibernate的程序要么采用自行编写的基于 ThreadLocal的上下文session,要么采用HibernateUtil这样的辅助类,要么采用第三方框架(比如Spring或Pico), 它们提供了基于代理(proxy)或者基于拦截器(interception)的上下文相关session。 
从3.0.1版本开 始,Hibernate增加了SessionFactory.getCurrentSession()方法。一开始,它假定了采用JTA事务,JTA事务 定义了当前session的范围和上下文(scope and context)。Hibernate开发团队坚信,因为有好几个独立的JTA TransactionManager实现稳定可用,不论是否被部署到一个J2EE容器中,大多数(假若不是所有的)应用程序都应该采用JTA事务管理。 基于这一点,采用JTA的上下文相关session可以满足你一切需要。 
更好的是,从3.1开 始,SessionFactory.getCurrentSession()的后台实现是可拔插的。因此,我们引入了新的扩展接口 (org.hibernate.context.CurrentSessionContext)和新的配置参数 (hibernate.current_session_context_class),以便对什么是“当前session”的范围和上下文(scope and context)的定义进行拔插。 

请参阅 org.hibernate.context.CurrentSessionContext接口的Javadoc,那里有关于它的契约的详细讨论。它定义 了单一的方法,currentSession(),特定的实现用它来负责跟踪当前的上下文session。Hibernate内置了此接口的两种实现。 
org.hibernate.context.JTASessionContext - 当前session根据JTA来跟踪和界定。这和以前的仅支持JTA的方法是完全一样的。详情请参阅Javadoc。 
org.hibernate.context.ThreadLocalSessionContext - 当前session通过当前执行的线程来跟踪和界定。详情也请参阅Javadoc。 

这 两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作session-per-request。Hibernate session的起始和终结由数据库事务的生存来控制。假若你采用自行编写代码来管理事务(比如,在纯粹的J2SE,或者 JTA/UserTransaction/BMT),建议你使用Hibernate Transaction API来把底层事务实现从你的代码中隐藏掉。如果你在支持CMT的EJB容器中执行,事务边界是声明式定义的,你不需要在代码中进行任何事务或 session管理操作。请参阅第 11 章 事务和并发一节来阅读更多的内容和示例代码。 


hibernate.current_session_context_class 配置参数定义了应该采用哪个org.hibernate.context.CurrentSessionContext实现。注意,为了向下兼容,如果未 配置此参数,但是存在org.hibernate.transaction.TransactionManagerLookup的配 置,Hibernate会采用org.hibernate.context.JTASessionContext。一般而言,此参数的值指明了要使用的实 现类的全名,但那两个内置的实现可以使用简写,即"jta"和"thread"





sss



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值