Hibernate3回顾-3-Session管理
3.Session管理
仅为个人理解.请指正
3.1背景
由于Configuration的创建耗费系统的资源。所以有必要只将Configuration实例化一次,之后通过SessionFactory获取session会话。一般都会手动封装一个HibernateUtil类(未使用Spring管理的前提下). 该类的作用使Hibernate加载配置文件config, 创建sessionFactory等只运行一次. 如下代码:
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
在静态方法中实例化,获取sessionFactory的实例。然后通过getSessionFactory().getOpenSession();
获取session。
类似的,之前有一种相对原始简单的进一步封装方式。如下:可见这种简单的封装进一步把增删改查等需求打包。
package com.test.util; import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration; /**
* 工具类网络优化版
*/
public final class HibernateUtil2 { //final类不允许被继承 {
private static SessionFactory sessionFactory; //私有静态属性
private static ThreadLocal session = new ThreadLocal(); private HibernateUtil2() { //私有的构造方法 禁止实例化
} static { //static块只会在虚拟机进行加载时被执行一次
Configuration cfg = new Configuration();
cfg.configure(); //读取配置文件信息,默认配置文件是"hibernate.cfg.xml"
sessionFactory = cfg.buildSessionFactory();
} public static Session getThreadLocalSession() {
Session s = (Session) session.get();
if (s == null) {
s = getSession();
session.set(s);
}
return s;
} public static void closeSession() {
Session s = (Session) session.get();
if (s != null) {
s.close();
session.set(null);
}
} public static SessionFactory getSessionFactory() {
return sessionFactory;
} public static Session getSession() {
return sessionFactory.openSession();
}
//数据库操作:增
public static void add(Object entity) {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil2.getSession();
tx = s.beginTransaction();
s.save(entity);
tx.commit();
} finally { //确保Session被关闭
if (s != null)
s.close();
}
}
//数据库操作:改
public static void update(Object entity) {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil2.getSession();
tx = s.beginTransaction();
s.update(entity);
tx.commit();
} finally {
if (s != null)
s.close();
}
}
//数据库操作:删
public static void delete(Object entity) {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil2.getSession();
tx = s.beginTransaction();
s.delete(entity);
tx.commit();
} finally {
if (s != null)
s.close();
}
}
//数据库操作:查询 通过主键id查询数据库中一个表的一行信息。Class 对应数据库表 或者 domain中的实体对象类,Serializable 序列号
public static Object get(Class clazz, Serializable id) {
Session s = null;
try {
s = HibernateUtil2.getSession();
Object obj = s.get(clazz, id);
return obj;
} finally {
if (s != null)
s.close();
}
}
}
3.2 使用ThreadLocal管理session
总而言之:在HibernateUtil类中封装hibernate的管理.通过openSession取得 session,并将其放入ThreadLocal变量中. 这样业务逻辑中仅需通过工具类取得当前线程对应的session.使用完毕后,将 session关闭,将当前线程的ThreadLocal变量置为NULL. 保证线程归还线程池复用后,ThreadLocal为空,以免出现导致其他线程访问到本线程变量.
详细:
Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,多个并发的线程可以同时访问一个SessionFactory并从中获取Session实例,那么Session是否是线程安全的呢?很遗憾,答案是否定的。Session中包含了数据库操作相关的状态信息,那么说如果多个线程同时使用一个Session实例进行CRUD,就很有可能导致数据存取的混乱,你能够想像那些你根本不能预测执行顺序的线程对你的一条记录进行操作的情形吗? 在Session的众多管理方案中,我们今天来认识一种名为ThreadLocal模式的解决方案。ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有一个该变量。
那麽具体如何利用ThreadLocal来管理Session呢?Hibernate官方文档手册的示例之中,提供了一个通过ThreadLocal维护Session的好榜样:
package com.test.util; import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; public class HibernateUtil_Thread {
public static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static final ThreadLocal<Session> session = new ThreadLocal<Session>(); public static Session currentSession() throws HibernateException {
Session s = session.get();
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
} public static void closeSession() throws HibernateException {
Session s = session.get();
if (s != null) {
s.close();
}
session.set(null);
}
}
使用eclipse工具也会生成类似上面的代码。如下:
package com.test.db; import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.AnnotationConfiguration;
/**
* 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.cfg.xml";
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new AnnotationConfiguration();
private static org.hibernate.SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION; static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
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;
} /**
* 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();
}
} /**
* 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;
} /**
* return hibernate configuration
*
*/
public static Configuration getConfiguration() {
return configuration;
}
}
3.3 新的解决方案:getCurrentSession
总而言之:Hibernate的SessionFactory提供获取session的新方法getCurrentSession (获得与当前线程绑定的session). 内部通过代理封装,此方式得到的session 不仅和当前线程绑定,也无需手动开关. 默认在事务提交之后,session自动关闭. 此外hibernate.cfg.xml配置文件中也需配置
使用 Hibernate 的大多数应用程序需要某种形式的“上下文相关的”会话,特定的会话在整个特定的上下文范围内始终有效。然后不同应用程序中对“上下文”一词的定义和理解是不同的。
在Hibernate3.0之前,使用Hibernate的程序要么自行编写基于ThreadLocal的上下文会话,要么采用HibernateUtil这样的辅助类,要么使用第三方框架(如spring或pico),他们提供了基于代理或者基于拦截器的上下文相关会话。
Hibernate 3.1之后,Hibernate增加了SessionFactory.getCurrentSession()方法。该方法实现是可拔插的(通过org.hibernate.context.CurrentSessionContext)和新的配置参数
(hibernate.current_session_context_class),以便对什么是当前会话的范围(scope)和上下文(context)的定义进行拔插。
请参阅 org.hibernate.context.CurrentSessionContext接口的 Javadoc,那里有关于它的契约的详
细讨论。它定义了单一的方法,currentSession(),特定的实现用它来负责跟踪当前的上下文相关
的会话。Hibernate 内置了此接口的三种实现:
•org.hibernate.context.JTASessionContext:当前会话根据 JTA 来跟踪和界定。这和以前的仅支
持 JTA 的方法是完全一样的。详情请参阅 Javadoc。
•org.hibernate.context.ThreadLocalSessionContext:当前会话通过当前执行的线程来跟踪和界
定。详情也请参阅 Javadoc。
•org.hibernate.context.ManagedSessionContext:当前会话通过当前执行的线程来跟踪和界定。但
是,你需要负责使用这个类的静态方法将 Session 实例绑定、或者取消绑定,它并不会打开
(open)、flush 或者关闭(close)任何 Session。
这两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作每次请求对应一个session。Hibernate session的起始和终结由数据库事务的生存来控制。假若你采用自行编写代码来管理事务(比如,在纯粹的J2SE,或者JTA/UserTransaction/BMT),建议你使用Hibernate Transaction API来把底层事务实现从你的代码中隐藏掉。如果你在支持CMT的EJB容器中执行,事务边界是声明式定义的,你不需要在代码中进行任何事务或session管理操作。请参阅第 11 章 事务和并发一节来阅读更多的内容和示例代码。
hibernate.current_session_context_class 配置参数定义了应该采用哪个org.hibernate.context.CurrentSessionContext实现。注意,为了向下兼容,如果未配置此参数,但是存在org.hibernate.transaction.TransactionManagerLookup的配置,Hibernate会采用org.hibernate.context.JTASessionContext。一般而言,此参数的值指明了要使用的实现类的全名,但那两个内置的实现可以使用简写,即"jta"和"thread"。
常见混淆
1 getCurrentSession创建的session会和绑定到当前线程,而openSession不会。
2 getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭
这里getCurrentSession本地事务(本地事务:jdbc)时 要在配置文件里进行如下设置
* 如果使用的是本地事务(jdbc事务) <property name="hibernate.current_session_context_class">thread</property> * 如果使用的是全局事务(jta事务) <property name="hibernate.current_session_context_class">jta</property>
getCurrentSession () 使用当前的session openSession() 重新建立一个新的session
在一个应用程序中,如果DAO 层使用Spring 的hibernate 模板,通过Spring 来控制session 的生命周期,则首选getCurrentSession ()。
Hibernate3回顾-3-Session管理的更多相关文章
- Spring aop与HibernateTemplate——session管理(每事务一次 Session)
一.HibernateTemplate与Spring aop简介 参见http://bbs.csdn.net/topics/340207475中网友blueram的发言.(感谢blueram) 二.在 ...
- Nhibernate的Session管理
参考:http://www.cnblogs.com/renrenqq/archive/2006/08/04/467688.html 但这个方法还不能解决Session缓存问题,由于创建Session需 ...
- Openfire的启动过程与session管理
说明 本文源码基于Openfire4.0.2. Openfire的启动 Openfire的启动过程非常的简单,通过一个入口初始化lib目录下的openfire.jar包,并启动一个 ...
- ABP(现代ASP.NET样板开发框架)系列之7、ABP Session管理
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之7.ABP Session管理 ABP是“ASP.NET Boilerplate Project (ASP.NET ...
- 2016-1-30 Servlet中Session管理(Sesssion追踪)
Session管理(Sesssion追踪)是Web应用程序开发中非常重要的一个主题.这是因为HTTP是无状态的,在默认情况下,Web服务器不知道一个HTTP请求是来自初次用户,还是来自之前已经访问过的 ...
- Redis3.2+Tomcat实现集群的Session管理 -- tomcat-redis-session-manager的编译和开发部署环境搭建
已经有不少文章介绍使用tomcat-redis-session-manager来实现Redis存储Tomcat的Session,实现分布式Session管理.但是现在官方编译的tomcat-redis ...
- tomcat架构分析 (Session管理)
Session管理是JavaEE容器比较重要的一部分,在app中也经常会用到.在开发app时,我们只是获取一个session,然后向session中存取数据,然后再销毁session.那么如何产生se ...
- Session管理解决方案笔记
大型网站Session管理解决方案: 1. web服务器之间的session复制. 优点:方案成熟 缺点:复制的性能开销大 2. 减少session使用,使用客户端存储cookie ...
- 使用Memcached Session Manager扩展Session管理
>>Tomcat的session管理 在请求过程中首先要解析请求中的sessionId信息,然后将sessionId存储到request的参数列表中. 然后再从request获取sessi ...
随机推荐
- Java 中空指针处理方法
空指针异常(Null Pointer Exception)是我们平时最容易碰到的,也是最令人讨厌的异常.本文介绍如何避免出现空指针异常. 首先我们看如下的示例: private Boolean isF ...
- 一张图让你学会LVM
导读 随着科技的进步,人们不知不觉的就进入了大数据的时代,数据的不断增加我们发现我们的磁盘越来越不够用了,接下来就是令人头疼的事情--加硬盘,数据的备份与还原.LVM就是Linux下专门针对我们数据的 ...
- XUtils解析
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ...
- 使用ASP.NET web API创建REST服务(三)
本文档来源于:http://www.cnblogs.com/madyina/p/3390773.html Creating a REST service using ASP.NET Web API A ...
- Oracle语句
分页查询: select rn,last_name,salary from( select rownum rn,last_name,salary from( select last_name,sala ...
- uva624 CD 01背包+输出最优解
link:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- sgu546 Ternary Password
题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=546 这题还好,1Y,考虑情况周全,就没问题了,还好提交之前把想到的情况都测试了一遍 ...
- 第五课,T语言转义字符()(版本5.0)
转义字符 字符串取值没什么限制,在引号""中可以填:数字.中文.字母 .特殊字符.以及他们的组合,字符串的值都要用双引号扩起来,比如 "我是字符型",当然,有人 ...
- HDU-3586 Information Disturbing(树形DP+删边)
题目大意:一棵有n个节点的有根树,1为根节点,边带权,表示删掉这条边的代价.现在要删掉一些边,使叶子节点不能到达根节点.但是,每次删除的边的代价不能超过limit,删掉的边的总代价不能超过m,求最小的 ...
- c语言开发手机通讯录
// // main.c // 手机通讯录 // // Created by Kevin-Dfg on 16/4/19. // Copyright © 2016年 Kevin-Dfg. All ...