Hibernate学习(一)
一、使用单例初始化SessionFactory
SessionFactory接口负责HIbernate的初始化和建立Session对象。它在Hibernate中起到一个缓冲区的作用,HIbernate可以将自动生成的SQL语句、映射数据以及某些可重复利用的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。
SessionFactory具有以下特点:
- 它是线程安全的,它的的同一个实例能够多个线程共享。
- 它是重量级的,不能随意创建和销毁它的实例。
由于SessionFactory的这些特点,一般情况下,一个项目只需要一个SessionFactory,只有在应用中存在多个数据源时,才为每个数据源建立一个SessionFactory实例。可以建立一个HibernateUtils.java类初始化SessionFactory使项目使用的是同一个SessionFactory。代码如下:
package com.test.util;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.SessionFactory;
public class HibernateUtils {
private static Configuration conf;
private static SessionFactory factory;
static{
conf = new Configuration().configure();
factory = conf.buildSessionFactory();
}
public static SessionFactory getFactory(){
return factory;
}
}
二、线程安全的Session
创建SessionFactory实例后,就可以通过它获取Session实例。获取Session实例有两种方式,一种是通过openSession()方法,另一种是通过getCurrentSession()方法。
这两种方法的区别是:采用openSession方法获取Session实例时,SessionFactory直接创建一个新的实例,并且在使用完成后需要调用close方法进行手动关闭。而getCurrentSession方法创建的Session实例会绑定到当前线程中,它会在提交或回滚操作时自动关闭。
Session是线程不安全的,多个线程同时操作一个Session实例时,就可能造成线程混乱。
我们可以改写HibernateUtils工具类实现线程安全的Session。代码如下:
package com.test.util;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.SessionFactory;
public class HibernateUtils {
private static Configuration conf;
private static SessionFactory factory;
private static ThreadLocal<Session> session = new ThreadLocal();
static{
conf = new Configuration().configure();
factory = conf.buildSessionFactory();
}
public static Session getSession(){
Session s = session.get();
if(s == null){
s = factory.getCurrentSession();
session.set(s);
}
return s;
}
public static void closeSession(){
Session s = session.get();
if (s != null) {
session.set(null);
}
}
}
ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每 一个线程都完全拥有一个该变量。具体关于ThreadLocal的详细知识可以自行去查一下。
三、遇到的问题
在使用getCurrentSession是遇到了以下错误
org.hibernate.HibernateException: No CurrentSessionContext configured!
是因为在hibernate.cfg.xml文件中忘记进行了如下设置:
如果是在web容器中运行hibernate,则在hibernate.cfg.xml中加入这句话:
<property name="hibernate.current_session_context_class">jta</property>
如果是在一个单独的需要进行JDBC连接的java application中运行hibernate,则这样设置:
<property name="hibernate.current_session_context_class">thread</property>