Hibernate用ThreadLocal模式(线程局部变量模式)管理Session
作者:徐刘根
Hibernate ThreadLocal
它会为每个线程维护一个私有的变量空间。实际上, 其实现原理是在JVM 中维护一个Map,这个Map的key 就是当前的线程对象,而value则是 线程通过Hibernate ThreadLocal.set方法保存的对象实例。当线程调用Hibernate ThreadLocal.get方法时, Hibernate ThreadLocal会根据当前线程对象的引用,取出Map中对应的对象返回。
这样,Hibernate ThreadLocal通过以各个线程对象的引用作为区分,从而将不同线程的变量隔离开来。
一、ThreadLocal模式 (线程局部变量模式) 管理Session的理解
(1)在利用Hibernate开发的时候如何合理的管理Session,避免Session的频繁创建和销毁,对于提高系统的性能来说是非常重要的!
(2)我们知道Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,多个并发的线程可以同时访问一个SessionFactory并从中获取Session实例,但是遗憾的是Session不是线程安全的。
(3)Session中包含了数据库操作相关的状态信息,那么说如果多个线程同时使用一个Session实例进行CRUD(数据库的增删改查),就很有可能导致数据存取的混乱,我们根本无法想像那些你根本不能预测执行顺序的线程对你的一条记录进行操作的情形!
(4)在Session的众多管理方案中,在今天的学习中知道ThreadLocal模式是一种很不错的解决方案,特分享给大家!
(5)我们首先要明白的是ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。(也许把它命名为ThreadLocalVar更加合适)。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用某变量的线程都提供一个该变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有一个该变量。
(6)更具体的来说就是:ThreadLocal并非等同于线程成员变量,ThreadLocal该类提供了线程局部变量。这个局部变量与一般的成员变量不一样,ThreadLocal的变量在被多个线程使用时候,每个线程只能拿到该变量的一个副本,这是Java API中的描述,但更准确的说,应该是ThreadLocal类型的变量内部的注册表(Map<Thread,T>)发生了变化,但ThreadLocal类型的变量本身的确是一个,这才是本质!
(7)ThreadLocal的原理:在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。比如下面的示例实现:
public class ThreadLocal { <span style="white-space:pre"> </span>private Map values = Collections.synchronizedMap(new HashMap()); <span style="white-space:pre"> </span>public Object get() { <span style="white-space:pre"> </span>Thread curThread = Thread.currentThread(); <span style="white-space:pre"> </span>Object o = values.get(curThread); <span style="white-space:pre"> </span>if (o == null && !values.containsKey(curThread)) { <span style="white-space:pre"> </span>o = initialValue(); <span style="white-space:pre"> </span>values.put(curThread, o); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>values.put(Thread.currentThread(), newValue); <span style="white-space:pre"> </span>return o; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>public Object initialValue() { <span style="white-space:pre"> </span>return null; <span style="white-space:pre"> </span>} }
二、代码的展示
(1)使用ThreadLocal模式 (线程局部变量模式) 管理Session的代码如下:
<span style="font-family:System;font-size:14px;">package com.lc.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * 升级的MySessionFactory 线程局部模式 * @author xuliugen */ public class HibernateUtil { private static SessionFactory sessionFactory = null; // 使用线程局部模式 private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); /* * 默认的构造函数 */ private HibernateUtil() { } /* * 静态的代码块 */ static { sessionFactory = new Configuration().configure().buildSessionFactory(); } /* * 获取全新的的session */ public static Session openSession() { return sessionFactory.openSession(); } /* * 获取和线程关联的session */ public static Session getCurrentSession() { Session session = threadLocal.get(); // 判断是是是否得到 if (session == null) { session = sessionFactory.openSession(); // 把session放到 threadLocal,相当于该session已经于线程绑定 threadLocal.set(session); } return session; } }</span>
(2)测试代码如下:
<span style="font-family:System;font-size:14px;">package com.lc.view; import org.hibernate.Session; import com.lc.util.HibernateUtil; public class TestHibernateUtil { public static void main(String[] args) { Session s1 = HibernateUtil.getCurrentSession(); Session s2 = HibernateUtil.getCurrentSession(); System.out.println(s1.hashCode()+" "+s2.hashCode()); /* * 1432950766 1432950766 * 结果是两个hashCode是一样的,证明是线程相关的 */ } }</span><span style="font-family:System;font-size:14px;"> </span>
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接