Hibernate 的会话工厂
1. 前言
Hibernate 的核心价值观是:开发者们!做你们应该做的。脏的、累的、没技术含义的由本尊来做。
本节课和大家一起好好的聊聊 Hibernate 的核心组件之一:会话工厂(SessionFactory)。
通过本节课,你将学习到:
- 会话工厂的设计要求;
- 会话工厂的核心功能。
2. 会话工厂的作用
原生 Jdbc 开发如同自己炒菜做饭,需经手买菜、洗菜、做菜……一系列过程。
基于 Hibernate 框架开发类似找一家餐馆就餐,只需要坐在那里,订一份菜单,稍等便会有色相味俱全的菜品出现在面前。
餐馆并没有省略买菜、洗菜、做菜一系操作,对于顾客而言,这些由餐馆内部工作人员完成。
Hibernate 框架与此类似,原生 JDBC 开发的过程中一系列的标准流程一样也不能少,只是由内部组件替代完成。
可把餐馆当成一个出品菜肴的工厂,为就餐者承担起一系列脏活、累活……
Hibernate 提供了一个 SessionFactory(会话工厂)对象,任劳任怨地为开发者承担起 Jdbc 开发流程中底层的繁琐事务操作。
概括会话工厂(SessionFactory)的功能:
- 为开发者屏蔽创建会话对象(session)时的一系列繁琐事宜,让开发者简单、直接获取 Session 对象,快速迭代自己的代码功能;
- 可根据开发者在主配置文件中的配置需求,提供高级辅助功能(如数据库连接池……);
- 会话工厂可缓存生成的 SQL 语句和 Hibernate 在运行时使用的映射元数据。
SessionFactory 类的设计顾名思议使用到工厂设计模式。经常会在一些框架程序中看到工厂设计模式,工厂设计模式的知名度如此之高,是由它自身的优势决定的:
- 工厂对象替开发者完成创建对象的细枝末节,让开发者只需专注于如何运用对象;
- 工厂对象内部可提供创建对象的优化方案,避免因开发者随意创建对象所带来的内存消耗。
古人打猎,需要用一周时间打磨工具,用一天时间捕捉猎物。现代人打猎前,可以去商店买一把猎枪,然后尽情享受打猎过程(保护野生动物,禁止打猎!)。
工厂设计模式对开发者说:享受开发吧!少年……
SessionFactory 从功能来讲似乎简单明了,创建 Session(其实这把猎枪不简单)。
使用细节需要开发者了解:
- SessionFactory 可看成对某一个具体数据库系统的抽象映射;
- 项目不涉及多数据源时,整个应用程序只需要一个会话工厂,可在应用初始化时创建;
- 多线程环境下,因 SessionFactory 需要在线程间共享,设计时考虑到了线程安全性问题,内部属性多使用 final 关键字修饰;
- 如果使用 Hibernate 访问多个数据库,则需要对每一个数据库使用一个 SessionFactory。
综上所述:
- 实用生产级别项目中,建议使用单例设计模式封装 SessionFactory 的创建,保证其应用程序作用域中的唯一性;
- 尽量不要在封装类中使用全局实例变量存储数据,避开线程安全性问题。
3. 单例设计模式封装会话工厂的创建
测试环境是一个演示、求证过程,测试一次创建一个 SessionFactory 对象并没有什么不妥。
生产环境则不同,代码结构上设计如果有缺陷,或者不遵循对象本身的特性需求。产品上线后,可能会因为产品的设计缺陷给客户造成某种程度上的损失。
报酬拿不到事小,丢失市场信任事大。
使用 HibernateSessionFactory 对象封装 SessionFactory 的创建:
public class HibernateSessionFactory {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
private static ServiceRegistry serviceRegistry;
//加载类时创建会话工厂对象
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(*configuration*.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
session = (sessionFactory != null) ? sessionFactory.openSession():null;
threadLocal.set(session);
}
return session;
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
}
HibernateSessionFactory 类内有很多代码值得细细品味,本节课你只需要关注单例设计模式实现要素:
- 构造方法私有化,创建对象的能力由内部决定,阻止外部非法任意创建;
private HibernateSessionFactory() {
}
- SessionFactory 在类的静态代码块内创建;
private static org.hibernate.SessionFactory sessionFactory;
//创建会话工厂,只会执行一次,也就只有一个对象
static {
//省略……
}
- 提供公开方法允许外部调用;
public static org.hibernate.SessionFactory getSessionFactory() {
//直接返回内部创建的会话工厂对象
return sessionFactory;
}
无论外部调用 getSessionFactory()方法多少次,最后创建的都只会有一个 SessionFactory 对象。
HibernateSessionFactory 类其它精华代码留到下一节课程。
4. 小结
工厂、工厂又见工厂!
工厂设计模式是一种屏蔽底层细节,为开发者创建高质量对象的优秀设计方案。怎么表扬这种设计模式都不为过。
到了本节课程说再见时刻,建议开发者,通过本节课程的学习,不仅要理解、掌握 Hibernate 中会话工厂的使用,更能把工厂模式很好地运用到自己的真实项目中。
既要学会使用 Hibernate,也要掌握其内在核心思想。