使用Eclipse生成Hibernate 代码时候工具为我们生成了一个 HibernateSessionFactory 这样的类 来为我们提供获得Session的方法. 但是用这个类的时候我们发现一个问题. 看下面代码
Session session1= HibernateSessionFactory.getSession();
Session session2 = HibernateSessionFactory.getSession();
System.out.println(session1+"__"+session2);
System.out.print(session1==session2);
通过测试发现 session1==session2 结果为 true . 难道真的是单例的吗?
我们来看一下HibernateSessionFactory 中 getSession()的实现
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
在这个方法中我们看这样两行代码
1,Session session = (Session) threadLocal.get();
2,threadLocal.set(session);
这两行代码中 HibernateSessionFactory 在获得 session的时候是先去threadLocal上取 如果取到了就直接返回,取不到就 生成一个 并 通过set注册到当前线程上.
再来看一下 ThreadLocal 中 get ,set 的实现;
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
return (T)map.get(this);
// Maps are constructed lazily. if the map for this thread
// doesn't exist, create it, with this ThreadLocal and its
// initial value as its only entry.
T value = initialValue();
createMap(t, value);
return value;
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
从它的get,set方法的实现中我们可以看出ThreadLocal 是以一种单例注册表的机制(一个单例类中包含一组对象的聚集) 实现的 通过它的实现(createMap(t,value)) 我们可以发现. 它保证在一个线程上只能注册一个实例. 并且每个线程上可以注册一个实例.因为不同的线程下Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
代表不同的对象 如果 t 是一个新的线程 那么 或的的map就是为空的 . 所以 createMap(t,value) 就会把一个新的实例放到这个线程上.并注册到注册表(ThreadLocalMap)中.
也就是说如果你在多个线程下创建了多个session 那么这些session在没有关闭的情况下都被保存在注册表(ThreadLocalMap)中 . ThreadLocalMap 中保存的就是一组这样的session对象.而不是一个.
下面是一个测试用来证明这一点.:
class MySessionTest implements java.lang.Runnable{
Session session=null;
public void run()...{
session= HibernateSessionFactory.getSession();
System.out.println("创建完毕"+Thread.currentThread()+"::"+session);
}
public Session getSesssionByThread(){
return session;
}
}
在main方法中写.
MySessionTest t1 = new MySessionTest();
MySessionTest t2 = new MySessionTest();
Thread tt1 = new Thread(t1);
Thread tt2 = new Thread(t2);
tt1.start();
tt2.start();
tt1.sleep(1000);
tt2.sleep(1000);
Thread.sleep(1000);
//如果线程不睡眠 下面的语句会先执行 得不到正确的结果. 只有等t1 ,和 t2 将session创建完毕后才能输出.
System.out.println(t1.getSesssionByThread()==t2.getSesssionByThread());
通过测试发现 输出结果为false 也就证明了 在多线程环境下HibernateSessionFactory.getSession()创建的Session不是单例的 .
但是又遇到了一个问题. 假设我要在同一个线程上通过HibernateSessionFactory获得多个Session的实例怎么办呢?
我们不妨在HibernateSessionFactory 中自己扩展一个方法
public static Session getAnotherSession() throws HibernateException{
if (sessionFactory == null) {
rebuildSessionFactory();
}
return sessionFactory.openSession();
}
通过这个方法获得的session实例 都上重新创建的新的势力.
看下面的测试代码
Session session1= HibernateSessionFactory.getSession();
Session session2 = HibernateSessionFactory.getAnotherSession();
Session session3 = HibernateSessionFactory.getAnotherSession();
System.out.println(session1==session2);
System.out.println(session2==session3);
输出的结果为false ,false ; 也就是在同一线程下获得了3个不同的session实例.
因为HIbernateSessionFactory是单例的所以创建的SessionFactory也是单例的 .保证 SessionFactory 不被重复加载 ,而且扩展的这个方法.处在HIbernateSessionFactory 也不会重新去加载SessionFactory .
Eclipse为什么要把这个HIbernateSessionFactory获得的这个session定义为一个线程上只有一个实例呢?
个人认为:
1,session 在缓存在操作数据的时候应该具有隔离性. 也就是尽可能的将你要操做的一组数据放到同一个 session 缓存中 ,这样不至于在清理缓存的时候出现数据更新紊乱的情况.
2,session 不是线程安全的 , 在设计时候应该尽可能的避免多个线程共享一个session . 但又不能把session定义为单例. 所以就以一个线程上最多只能创建一个session实例 .并且每个线程都能创建一个实例.的这样一种单例注册表的机制来实现 .
关于单例类和单例注册表 可以参看我的另一片文章
http://blog.csdn.net/caoyinghui1986/archive/2008/05/22/2468180.aspx
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/caoyinghui1986/archive/2008/05/24/2476162.aspx
分享到:
相关推荐
HibernateSessionFactory.java
Session s= HibernateSessionFactory.getSession(); 就是Hibernate的工具java类
用于获得Session会话及关闭Session会话
Hibernate中涉及到的增加,删除,查询,修改,操作.
NULL 博文链接:https://chaoyi.iteye.com/blog/2148991
NULL 博文链接:https://zgdkik.iteye.com/blog/1835667
一个实例小工程,讲解的是将hibernate的sessionFactory交给spring管理的配置方法
(5)创建Hibernate的SessionFactory类。 (6)通过SessionFactory创建Session实例。 (7)通过创建的Session实例进行持久化对象的管理。 (8)通过创建的Transaction实例进行事务管理。 (9)通过创建的Query或...
修改了Hibernate的源码,可动态增加映射文件
Hibernate中的sessionFactory
import org.hibernate.Session; import org.hibernate.cfg.Configuration; /** * Configures and provides access to Hibernate sessions, tied to the * current thread of execution. Follows the Thread Local...
hibernate中的SessionFactoryhibernate中的SessionFactoryhibernate中的SessionFactory
(2)SessionFactory:初始化Hibernate,充当数据存储源的代理,创建Session对象。一个SessinFactory实例对应一个数据存储源,应用从SessionFactory中获得Session实例。如果应用同时访问多个DB,怎需要为每个数据库...
Hibernate的核心接口一共有6个,分别为:Session、SessionFactory、Transaction、Query、Criteria和Configuration。这6个核心接口在任何开发中都会用到。通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务...
Configuration configuration = new ...或者通过MyEclipse的Hibernate工具自动生成的HibernateSessionFactory.getSession()方法来获取Session,调用HibernateSessionFactory. closeSession()方法来关闭session。
是非线程安全的(尽管创建一个Session对象消耗的资源很小),所以在获取Session对象时候也最好用单例模式获取 3.提交并清空Session中缓存的数据后开始一个事务 Session对象.flush(); //将Session中的缓存内容提交到...
hibernateOperate.java DeleteTest.java HibernateSessionFactory.java BatchUpdateTest.java