@author:WMsteve
@Email:weisteve@yeah.net
@Time:2012年1月3日23:45:34
上一篇文章讲述了Hibernate工作的流程,此文详细介绍下SessionFactory的工作方式。
SessionFactory:它保存了对当前数据库配置的所有映射关系,它是将某个数据库的映射关系经过编译之后全部保存在内存中的。 它还是生成Session的工厂,它在进行实例化的过程中将会用到ConnectionProvider。一个SessionFactory对应一个数据库连接,当数据库连接改变时需要修改SessionFactory。
SessionFactory提供了数据库的连接实例,生成Session,它的正常工作需要读取一定的数据库连接配置参数。
下面详细讲述下SessionFactory初始化需要配置的参数:
属性 | 描述 |
dialect | 数据库的方言 |
connection.driver_class | 数据库驱动Jar包 |
connection.URL | 连接数据库的URL |
connection.username | 连接数据库的用户名 |
connection.password | 连接数据库的密码 |
show_sql | 是否输出sql语句 |
具体的一个SessionFactory配置如下:
<session
-factory
>
<property name = "dialect" >
org.hibernate.dialect.Oracle9Dialect
< /property >
<property name = "show_SQL" >true < /property >
<property name = "connection.url" >
jdbc :oracle :thin :@ 10. 4. 10. 92 : 1521 :DJoracle
< /property >
<property name = "connection.username" >DJUSER < /property >
<property name = "connection.password" >DongJiang2011 < /property >
<property name = "connection.driver_class" >
oracle.jdbc.driver.OracleDriver
< /property >
<property name = "myeclipse.connection.profile" >
Oracle 11 g_common
< /property >
<mapping resource = "com/dj/hibernate/DJDB_HI/StAddvcdD.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StAstrotdF.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StDayevR.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StEnnmcdD.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StEstatR.hbm.xml" / >
< /session -factory >
从上面的配置文件中可以看到上半部分的含义,下面<mapping resource部分后续在做详细介绍>
<property name = "dialect" >
org.hibernate.dialect.Oracle9Dialect
< /property >
<property name = "show_SQL" >true < /property >
<property name = "connection.url" >
jdbc :oracle :thin :@ 10. 4. 10. 92 : 1521 :DJoracle
< /property >
<property name = "connection.username" >DJUSER < /property >
<property name = "connection.password" >DongJiang2011 < /property >
<property name = "connection.driver_class" >
oracle.jdbc.driver.OracleDriver
< /property >
<property name = "myeclipse.connection.profile" >
Oracle 11 g_common
< /property >
<mapping resource = "com/dj/hibernate/DJDB_HI/StAddvcdD.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StAstrotdF.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StDayevR.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StEnnmcdD.hbm.xml" / >
<mapping resource = "com/dj/hibernate/DJDB_HI/StEstatR.hbm.xml" / >
< /session -factory >
上述是SessionFactory初始化需要的参数,具体的SessionFactory工作逻辑:
package com.dj.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.AnnotationConfiguration;
引入hibernate包
/**
* Configures and provides access to Hibernate sessions, tied to the
* current thread of execution. Follows the Thread Local Session
* pattern, see {@link http://hibernate.org/42.html }.
*/
public class HibernateSessionFactory {
/**
* Location of hibernate.cfg.xml file.
* Location should be on the classpath as Hibernate uses
* #resourceAsStream style lookup for its configuration file.
* The default classpath location of the hibernate config file is
* in the default package. Use #setConfigFile() to update
* the location of the configuration file for the current session.
*/
声明HibernateSessionFactory类,默认hibernate调用此类来完成sessionFactory创建。
* Configures and provides access to Hibernate sessions, tied to the
* current thread of execution. Follows the Thread Local Session
* pattern, see {@link http://hibernate.org/42.html }.
*/
public class HibernateSessionFactory {
/**
* Location of hibernate.cfg.xml file.
* Location should be on the classpath as Hibernate uses
* #resourceAsStream style lookup for its configuration file.
* The default classpath location of the hibernate config file is
* in the default package. Use #setConfigFile() to update
* the location of the configuration file for the current session.
*/
private
static String CONFIG_FILE_LOCATION
=
"/hibernate_common.xml";
定义默认载入的文件位置与文件名
private
static
final ThreadLocal
<Session
> threadLocal
=
new ThreadLocal
<Session
>();
在利用Hibernate开发DAO模块时,我们和Session打的交道最多,所以如何合理的管理Session,避免Session的频繁创建和销毁,对于提高系统的性能来说是非常重要的。我们知道Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,多个并发的线程可以同时访问一个SessionFactory并从中获取Session实例,那么Session是否是线程安全的呢?很遗憾,答案是否定的。Session中包含了数据库操作相关的状态信息,那么说如果多个线程同时使用一个Session实例进行CRUD,就很有可能导致数据存取的混乱,你能够想像那些你根本不能预测执行顺序的线程对你的一条记录进行操作的情形吗? 在Session的众多管理方案中,我们今天来认识一种名ThreadLocal模式的解决方案。早在Java1.2推出之时,Java平台中就引入了一个新的支持:java.lang.ThreadLocal,给我们在编写多线程程序时提供了一种新的选择。ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单, 就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有一个该变量。ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
private
static Configuration configuration
=
new AnnotationConfiguration();
private static org.hibernate.SessionFactory sessionFactory;
全局静态变量,在整个hibernate期间,只有一个实例存在,它是线程间安全的。
private static org.hibernate.SessionFactory sessionFactory;
private
static String configFile
= CONFIG_FILE_LOCATION;
配置文件名,最终查找配置文件时,使用的是configFile变量。
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println( "%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
首先根据配置的configFile创建configuration的实例。
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println( "%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
这里configuration采用了创建模型的Builder模型,辅助产生实例sessionFactory。
详细过程请查阅Builder模式。
利用configuration生成sessionFactory
在上述配置中,只有hibernate启动时执行。
private HibernateSessionFactory() {
}
构造函数
}
/**
* Returns the ThreadLocal Session instance. Lazy initialize
* the <code>SessionFactory</code> if needed.
*
* @return Session
* @throws HibernateException
*/
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
首先从threadLocal中获取一个session实例,如果取得session是空或者session是关闭状态。
* Returns the ThreadLocal Session instance. Lazy initialize
* the <code>SessionFactory</code> if needed.
*
* @return Session
* @throws HibernateException
*/
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
那么根据这两种情况进行不同的处理;如果是session为空,说明系统还没打开任何的session实例,这时需要新建一个session,放入threadLocal中,以备后续重复试用。如果sessionFactory是空,说明configFactory还没建立实例,通过rebuildSessionFactory生成sessionFactory实例,以便后续通过sessionFactory生成所需session。
/**
* Rebuild hibernate session factory
*
*/
public static void rebuildSessionFactory() {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println( "%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
根据定义的configFile重新建立针对configFile定义的数据库连接实例。
* Rebuild hibernate session factory
*
*/
public static void rebuildSessionFactory() {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println( "%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
/**
* Close the single hibernate session instance.
*
* @throws HibernateException
*/
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
关闭session连接。
* Close the single hibernate session instance.
*
* @throws HibernateException
*/
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
/**
* return session factory
*
*/
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
获取现有的SessionFactory实例
* return session factory
*
*/
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* return session factory
*
* session factory will be rebuilded in the next call
*/
public static void setConfigFile(String configFile) {
HibernateSessionFactory.configFile = configFile;
sessionFactory = null;
}
重新设置SessionFactory的配置文件路径。这里是如果所用数据源不是初始定义的配置文件,这里可以通过程序来更改配置,达到动态连接不同数据库的目的。
* return session factory
*
* session factory will be rebuilded in the next call
*/
public static void setConfigFile(String configFile) {
HibernateSessionFactory.configFile = configFile;
sessionFactory = null;
}
/**
* return hibernate configuration
*
*/
public static Configuration getConfiguration() {
return configuration;
}
获取配置类实例
* return hibernate configuration
*
*/
public static Configuration getConfiguration() {
return configuration;
}
}