【Hibernate】Hibernate构建单例SessionFactory

时间:2021-10-26 16:50:40

Hibernate常用的核心接口包括:

Configuration、SessionFactory、Session、Transaction、Query、Criteria。

在完成session获取的过程中,主要涉及Configuration、SessionFactory、Session接口。

Configuration接口:负责配置并启动Hibernate,创建SessionFactory对象。在Hibernate的启动过程中,Configuration类的实例首先定位映射文档位置,读取配置,然后创建SessionFactory对象。

SessionFactory接口:负责初始化Hibernate,并负责创建Session对象。这里用到了工厂模式,但是SessionFactory并不是轻量级的,因为在一般情况下,一个项目通常只需要一个SessionFactory就足够了,当需要操作多个数据库时,可以定义多个SessionFactory。

Session接口:负责执行被持久化对象的CRUD操作,但是Session对象是非线程安全的。

ThreadLocal类用于在并发环境下避免竞争,简化编程的机制,它在并发环境下提供了一个逻辑上全局的访问点,来访问线程本地变量。ThreadLocal的功能非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立的改变自己的副本,而不会和其他线程的副本冲突。从线程的角度来看,就好像每一个线程完全拥有该变量。

public class ThreadLocal {
//HashMap存储ThreadLocal变量,并实现了线程安全
private Map values = Collections.synchronizedMap(new HashMap());
public Object get(){
Thread curThread = Thread.currentThread();
Object obj = values.get(curThread);
if(obj==null&&!values.containsKey(curThread)){
obj = initialValue();
values.put(curThread, obj);
}
return obj;
}

public void set(Object newValue){
values.put(Thread.currentThread(), newValue);
}

public Object initialValue(){
return null;
}
}

SessionFactory在Hibernate中起到了一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和其他的映射数据,还缓冲了一些将来可能要重复利用的数据。首先介绍下Hibernate的传递配置属性的三种方式:

No.1 使用hibernate.cfg.xml:

Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml");

No.2 使用hibernate.properties:

Configuration cfg = new Configuration();
cfg.configure("/hibernate.properties");
cfg.addResource("com/demo/hibernate/beans/User.hbm.xml");

Configuration cfg = new Configuration();
cfg.configure("/hibernate.properties");
cfg.addClass(com.demo.hibernate.beans.User.class);

No.3 构造时硬编码:

Configuration cfg = new Configuration()
.addClass(com.demo.hibernate.beans.User.class)
.setProperty("hibernate.dialect","org.hibernate.dialect.MySQLInnoDBDialect");
.setProperty("hibernate.connection","java:com/env/jdbc.test");
.setProperty("hibernate.order_updates","true");

我们知道Configuration实例是一个启动期间(sartup-time)的对象,一旦SessionFactory创建完成她就被丢弃。对于SessionFactory来说,它采用了工厂模式,用户程序从工厂类SessionFactory中取得Session的实例,它的设计者的意图是让她在整个应用*享。典型地说,一个项目通常只需要一个SessionFactory就足够了。因此,我们可以这样定义SessionFactory类:

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;


public class HibernateSessionFactory {
private static final Configuration cfg = new Configuration();
private static org.hibernate.SessionFactory sessionFactory;
private static final ThreadLocal threadLocal = new ThreadLocal();

public static Session currentSession() throws HibernateException{
Session session = (Session)threadLocal.get();
if(session == null){
if(sessionFactory == null){
try{
cfg.configure("hibernate.cfg.xml");
sessionFactory = cfg.buildSessionFactory();
}catch(HibernateException e){
System.out.println("Error Creating SessionFacotry.");
e.printStackTrace();
}
}
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}

public static void cloaseSession() throws HibernateException{
Session session = (Session)threadLocal.get();
threadLocal.set(null);
if(session != null){
session.close();
}
}
}
总之,ThreadLocal让一次程序的运行来使用一个Session,而所有的Session都公用一个SessionFacotry,这样做有3个好处:

让所有用户共用一个SessionFactory,避免了重复创建SessionFactory而造成的资源浪费;

为每一个用户访问都创建一个Session,避免了不同用户之间的Session冲突;

在每一次程序运行的周期内,共用一个Session,既可以避免资源浪费,有提供了资源的共享,让一次运行的多个操作共用一个Session资源,为事务的操作也提供了基础。

因此,HibernateSessionFactory创建的实例关系图如下:
【Hibernate】Hibernate构建单例SessionFactory

整个系统只有一个Configuration和SessionFactory对象,而不同的用户访问有不同的SessionA和SessionB。每一个Session在生命期内,都可以进行多个操作,直到线程访问结束。