6.Session管理
Java程序的运行起点要么是主线程,要么是主线程中启动的新线程。主方法(线程run方法)既是起点,也是终点,其它方法被上一层调用,也调用下一层,等待下一层返回,最终也会返回给上一层。
在每一次的调用中开始和结束都要开闭Session,频繁开闭Session不仅造成性能的浪费,上一层调用者获得下一层方法返回的实体对象(关联的session关闭后可能是游离态)仍然无法延迟加载,让延迟加载成了鸡肋 。
那么我们可以对Session进行管理,是Session成为在线程内可共享的Session,在整个线程中每次方法调用获得开启共享的Session实例,在线程结束时关闭Session。这样既减少了性能浪费,代码重复,有解决了一些在线程中延迟加载的问题。代码如下:
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
//产生SessionFactory实例
public class HibernateUtil {
private static SessionFactory sessionFactory;// 静态变量
//这相当于一个容器,从里面取出的变量是当前线程中变量的副本
public static final ThreadLocal<Session> HIBERNATE_SESSION_LOCAL = new ThreadLocal<Session>();
static {// 静态初始化块
try {
Configuration cfg = new Configuration().configure("/cfg/hibernate.xml");
// Hibernate4提供的新方式
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(cfg.getProperties()).buildServiceRegistry();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
/**
* 获取线程内共享的Session实例
* @return
*/
public Session currentSession(){
Session session = HIBERNATE_SESSION_LOCAL.get();//取出本地变量
if(session == null){//如果没有
session = getSession();//新建Session实例
HIBERNATE_SESSION_LOCAL.set(session);//存放本地变量
}
return session;
}
/**
* 关闭线程内共享的Session实例
*/
public void closeCurrentSession(){
try {
currentSession().close();
} catch (Exception e) {
// e.printStackTrace();
}
}
/**
* 开启一个新的Session
* @return
*/
public Session getSession(){
return sessionFactory.openSession();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
getSessionFactory().close();
}
}
我们可以在一下情况关闭Session:
(1)Junit测试中可以在测试方法结束后关闭;
(2)CS结构中可在线程结束时关闭;
(3)BS-web结构中,可在一次请求结束后关闭。
在Junit测试是一个线程可以依次执行多个方法,所以我们需要在所有方法调用前开启事务,在所有方法完成后再提交事务并关闭Session,那么我们可以这样实现:
@BeforeClass
public static void beforeClass() throws Exception {
HibernateUtil.currentSession().beginTransaction();
}
@AfterClass
public static void afterClass() throws Exception {
HibernateUtil.currentSession().getTransaction().commit();
HibernateUtil.closeCurrentSession();
}