为什么我们为每条线程创建自己的Session实例:
- SessionFactory是线程安全的(Thread-Safe),可以让多个执行线程同时存取SessionFactory而不会有数据共享的问题。
- 会话工厂缓存了生成的SQL语句和Hibernate在运行时使用的映射元数据。
- 需要注意的是SessionFactory是重量级的,因为一 般情况下,一个项目通常只需要一个SessionFactory就够(单例模式),当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流):
- Session也称为持久化管理器,因为它是与持久化有关的操作接口。
- Session不是线程安全的,应该避免多个线程共享同一个Session实例。
- Session通过SessionFactory打开,在所有的工作完成后,需要关闭。
其中可以通过以下方式实现每一个线程中有一个Session实例
- getCurrentSession (Hibernate 3)
- 可以采用ThreadLocal的办法。(Hibernate 2)
- 把Session对象放在方法内部定义
下面我们采用第二种方法(ThreadLocal)来实现它。
import java.util.function.*;
import org.hibernate.*;
import org.hibernate.cfg.*;
public class Util
{
private static final SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
private static final ThreadLocal<Session> threadLocal=ThreadLocal.withInitial(new Supplier<Session>()
{
public Session get()
{
return sessionFactory.openSession();
}
});
public static Session getSession()
{
//由"ThreadLocal.withInitial"中的Supplier参数确保get返回值必不为空。
return threadLocal.get();
}
public static void closeSession()
{
//由"ThreadLocal.withInitial"中的Supplier参数确保get返回值必不为空。
threadLocal.get().close();
//移除ThreadLocal中的Session,确保下次调用get方法重新调用"ThreadLocal.withInitial"中的Supplier参数。
threadLocal.remove();
}
}