`

Hibernate中使用Threadlocal创建线程安全的Session

 
阅读更多

一、问题的提出
 
 
 我们知道Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,多个并发的线程可以同时访问一 个SessionFactory并从中获取Session实例,而Session不是线程安全的。Session中包含了数 据库操作相关的状态信息,那么说如果多个线程同时使用一个Session实例进行CRUD,就很有可能导致数据存
取的混乱,你能够想像那些你根本不能预测 执行顺序的线程对你的一条记录进行操作的情形吗?
二、 解决方案思路
使用Threadlocal类集合

    早在Java1.2推出之时,Java平台中就引入了一个新的支持:java.lang.ThreadLocal,给我们在编写多线程程序时提供了一种新 的选择。ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单, 就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每 一个线程都完全拥有一个该变量。
    ThreadLocal这个类本身不是代表线程要访问的变量,这个类的成员变量才是。JDK1.5给ThreadLocal加了泛型功能,即是 ThreadLocal,这个泛型T即是要线程的本地变量。线程通过ThreadLocal的get和set方法去访问这个变量T。
    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);  
            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;  
        
   }

三、解决方案步骤

   1、在HibernateUtil类中我们需要定义一个静态的成员变量用于保存当前线程共用的Session

    public class HibernateUtil {
    private static SessionFactory factory;
    // 使用ThreadLocal集合保存当前业务线程中的SESSION
    private static ThreadLocal session = new ThreadLocal();

    static {
        // 第一步:读取HIBERNATE的配置文件,读取hibernate.cfg.xml文件
        Configuration con = new Configuration().configure();
        // 第二步:创建服务注册构建器对象,通过配置对象中加载所有的配置信息,存放到注册服务中
        ServiceRegistryBuilder regBuilder = new ServiceRegistryBuilder()
                .applySettings(con.getProperties());
        // 创建注册服务
        ServiceRegistry reg = regBuilder.buildServiceRegistry();
        // 第三步:创建会话工厂
        factory = con.buildSessionFactory(reg);
    }

   
    public static Session getLocalThreadSession() {
        Session s = session.get();// 获取当前线程下的SESSION
        if (s == null) {
            s = getFactory().getCurrentSession();// 获取当前线程中的SESSION,
需在在Hibernate.cfg.xml文件,具体请看面的说明
            session.set(s);// 将当前SESSION放入到当前线程的容器中保存
        }
        return s;
    }


    
    public static void closeSession() {
        Session s = session.get();// 获取当前线程下的SESSION
        if (s != null) {
            // s.close();//这里无需将Session关闭,因为该Session是保存在当前线程//中的,线程执行完毕Session自然会销毁
            session.set(null);// 将当前线程中的会话清除
        }
    }

}

2、添加OpenSessionInViewFilter过滤器(不要忘了在Web.xml配置该过滤器

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
Session s = HibernateUtil.getThreadLocalSession();
Transaction t = null;
try {
// 开始事务
t = s.beginTransaction();
// 进入一系列的过滤链,处理相应的ACTION、业务逻辑及数据层
filterChain.doFilter(request, response);
// 提交事务
t.commit();

} catch (Exception e) {
if (t != null)
    t.rollback();//出现异常回滚事务
throw new RuntimeException(e.getMessage(), e);

} finally {
    HibernateUtil.closeSession();
}
}

##############################################################################################

说明:关于getCurrentSession()方法:
    sessionFactory.getCurrentSession()获取当前线程中的Session, 当调用时,hibernate将session绑定到当前线程,事务结束后,hibernate将session从当前线程中释放,并且关闭 session。当再次调用getCurrentSession()时,将得到一个新的session,并重新开始这一系列工作。这样调用方法如下: Session session = HibernateUtil.getSessionFactory().getCurrentSession();

getCurrentSession和openSession的区别:
1、getCurrentSession创建的session会和绑定到当前线程,而openSession不会。
2、getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭
3、
getCurrentSession需在在Hibernate.cfg.xml文件中添加配置:
 
 <property name="current_session_context_class">thread</property>
四、总结

   这种解决方案的优缺点:

1、优点:使用ThreadLocal除了有避免频繁创建和销毁session的好处外, 还有一个特别大的好处,
就是可以做到多线程的数据隔离, 可以避免多个线程同时操作同一个session

2.缺点:  如下图



 
使用拦截器在响应返回时,又重复过滤了一次,延长了响应的时间(改进:我们可以把写在过滤器中的方法写在一个具体的类,用到的时候再调用)

  • 大小: 54.9 KB
分享到:
评论

相关推荐

    Hibernate用ThreadLocal模式(线程局部变量模式)管理Session

    具体到Hibernate中,我们可以创建一个ThreadLocal变量,用来持有每个线程的Session实例。每次线程需要访问Session时,通过ThreadLocal.get()方法获取当前线程对应的Session,而无需担心与其他线程的Session混淆。当...

    day36 11-Hibernate中的事务:当前线程中的session

    总的来说,理解并正确使用“当前线程中的Session”是Hibernate开发中的重要一环。它可以帮助我们更高效、安全地处理数据库事务,确保数据的完整性和一致性。在实际项目中,根据应用的需求和环境选择合适的事务管理...

    hibernate中session的管理

    首先,SessionFactory是Hibernate的核心组件,它是一个线程安全的工厂类,用于创建Session实例。SessionFactory通常在应用程序启动时初始化,并在整个应用生命周期内保持不变,因此它可以被多个并发线程共享。...

    ThreadLocal的几种误区

    1. 存储当前会话用户信息:例如,可以在一个线程中使用ThreadLocal保存用户的登录状态,确保每个线程只处理一个用户的信息。 2. 存放上下文变量:如WebWork的ActionContext,它可以保存请求处理过程中的各种上下文...

    Hibernager_Session_Manager_ThreadLocal

    总结起来,"Hibernage_Session_Manager_ThreadLocal"是一个关于使用ThreadLocal在多线程环境中优化Hibernate Session管理的技术实践,通过这种方式可以提升应用程序的性能和安全性。`HibernateUtil.java`是实现这一...

    JAVA ThreadLocal类深入

    例如,HibernateUtil类中会定义一个ThreadLocal变量来保存SessionFactory创建的Session实例,便于在多线程环境下安全地使用。 ```java public class HibernateUtil { private static final ThreadLocal&lt;Session&gt; ...

    hibernate常用方法集合

    `cfg.buildSessionFactory()`则根据配置创建SessionFactory单例,SessionFactory是负责创建Session实例的工厂类,它是线程安全的,适合在多线程环境中使用。 2. **ThreadLocal Session模式** `Hibernate...

    java 中ThreadLocal本地线程和同步机制的比较

    3. 在Spring或Hibernate等ORM框架中存放Session:每个线程拥有自己的数据库Session实例,确保事务的独立性。 例如,用ThreadLocal实现线程局部的Singleton模式,可以确保每个线程都有自己的Singleton实例,避免了...

    正确理解ThreadLocal.pdf

    在实际应用中,如上文所示的Hibernate示例,通过`set()`方法可以将`Session`对象与当前线程绑定,而`get()`方法则用于获取当前线程的`Session`对象。这种设计模式避免了在多线程环境中直接操作共享资源可能带来的...

    8个案例详解教会你ThreadLocal.docx

    例如,Spring 中的 TransactionTemplate 和 AOP 模块利用 `ThreadLocal` 存储当前事务信息,Hibernate 中的 Session 管理也依赖于 `ThreadLocal` 来保持线程绑定的 Session。 7. **线程安全** - `ThreadLocal` ...

    hibernate

    可以使用 `ThreadLocal` 变量来解决这个问题,确保每个线程都有自己的 `Session` 实例。 #### 三、使用 Hibernate 的基本步骤 **1. 创建 Configuration 对象** ```java Configuration config = new Configuration...

    ThreadLocal源码分析和使用

    ThreadLocal 源码分析和使用 ThreadLocal 是 Java 语言中的一种多线程编程机制,用于...在这个例子中,我们使用 ThreadLocal 来实现一个序列号生成器,每个线程都可以独立地生成序列号,而不会受到其他线程的影响。

    入研究java.lang.ThreadLocal类.docx

    - 使用 `ThreadLocal&lt;Session&gt;` 确保每个线程都有独立的 Session 实例。 - 通过 `initialValue()` 方法初始化每个线程的 Session。 - `currentSession()` 方法确保每次调用都能获取到当前线程的 Session 实例。 ###...

    java 中ThreadLocal 的正确用法

    // 创建线程局部变量 session,用来保存 Hibernate 的 Session private static ThreadLocal session = new ThreadLocal() { protected Object initialValue() { return sessionFactory.getCurrentSession(); } ...

    java面试题汇总

    例如,Hibernate框架中,使用ThreadLocal来存储每个线程的Session实例,这样每个线程都有自己的Session,避免了线程间的数据混乱。以下是一个简单的例子: ```java public static final ThreadLocal&lt;Session&gt; ...

    基于Hibernate的数据持久层关键技术的研究

    2. **ThreadLocal模式**:在多线程环境下,使用ThreadLocal来管理Hibernate的Session可以避免线程安全问题。每个线程都有自己的Session实例,这样可以确保数据访问的线程安全性。 3. **静态工厂方法**:为了提高...

    课程hibernate的事务和并发.pdf

    ThreadLocal变量可以绑定到处理请求的线程,使得代码能方便地访问Session,而事务上下文环境也可存储在ThreadLocal中,根据所选的事务划分机制进行管理。这种方式被称为ThreadLocal Session和Open Session in View...

    在Eclipse下开发Hibernate.pdf

    7. **SessionFactory**: SessionFactory是Hibernate的核心组件,它是线程安全的,负责创建Session对象。SessionFactory在应用启动时创建一次,之后在整个应用生命周期中重复使用。 8. **Session对象**: Session是与...

Global site tag (gtag.js) - Google Analytics