Hibernate学习笔记--使用ThreadLocal
参考资料:
http://blog.sina.com.cn/s/blog_7ffb8dd5010146i3.html
http://lavasoft.blog.51cto.com/62575/51926/
一、问题的提出
我们知道Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,多个并发的线程可以同时访问一 个SessionFactory并从中获取Session实例,而Session不是线程安全的。Session中包含了数 据库操作相关的状态信息,那么说如果多个线程同时使用一个Session实例进行CRUD,就很有可能导致数据存取的混乱,你能够想像那些你根本不能预测 执行顺序的线程对你的一条记录进行操作的情形吗?
二、 解决方案思路(使用Threadlocal类集合)
早在Java1.2推出之时,Java平台中就引入了一个新的支持:java.lang.ThreadLocal,给我们在编写多线程程序时提供了一种新 的选择。ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单, 就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每 一个线程都完全拥有一个该变量。
ThreadLocal这个类本身不是代表线程要访问的变量,这个类的成员变量才是。JDK1.5给ThreadLocal加了泛型功能,即是 ThreadLocal,这个泛型T即是要线程的本地变量。线程通过ThreadLocal的get和set方法去访问这个变量T。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。比如下面的示例实现(为了简单,没有考虑集合的泛型):
public class ThreadLocal {
private Map values = Collections.synchronizedMap(new HashMap());
public Object get() {
Thread currentThread = Thread.currentThread();
Object result = values.get(currentThread);
if(result == null&&!values.containsKey(currentThread)) {
result = initialValue();
values.put(currentThread, result);
}
return result;
}
public void set(Object newValue) {
values.put(Thread.currentThread(), newValue);
}
public Object initialValue() {
return null;
}
}
三、解决方案步骤
1、在HibernateUtil类中我们需要定义一个静态的成员变量用于保存当前线程共用的Session
public class HibernateUtil {
private static SessionFactory factory;
// 使用ThreadLocal集合保存当前业务线程中的SESSION
private static ThreadLocal threadlocal= new ThreadLocal(); static {
// 第一步:读取HIBERNATE的配置文件,读取hibernate.cfg.xml文件
Configuration con = new Configuration().configure();
// 第二步:创建服务注册构建器对象,通过配置对象中加载所有的配置信息,存放到注册服务中
ServiceRegistryBuilder regBuilder = new ServiceRegistryBuilder()
.applySettings(con.getProperties());
// 创建注册服务
ServiceRegistry reg = regBuilder.buildServiceRegistry();
// 第三步:创建会话工厂
factory = con.buildSessionFactory(reg);
} public static Session getLocalThreadSession() {
Session s = threadlocal.get();// 获取当前线程下的SESSION
if (s == null) {
s = getFactory().getCurrentSession();// 获取当前线程中的SESSION,需在在Hibernate.cfg.xml文件,具体请看面的说明
threadlocal.set(s);// 将当前SESSION放入到当前线程的容器中保存
}
return s;
} public static void closeSession() {
Session s = threadlocal.get();// 获取当前线程下的SESSION
if (s != null) {
// s.close();//这里无需将Session关闭,因为该Session是保存在当前线程//中的,线程执行完毕Session自然会销毁
threadlocal.set(null);// 将当前线程中的会话清除
}
} }
2、添加OpenSessionInViewFilter过滤器(不要忘了在Web.xml配置该过滤器)
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
Session s = HibernateUtil.getThreadLocalSession();
Transaction t = null;
try {
// 开始事务
t = s.beginTransaction();
// 进入一系列的过滤链,处理相应的ACTION、业务逻辑及数据层
filterChain.doFilter(request, response);
// 提交事务
t.commit();
} catch (Exception e) {
if (t != null)
t.rollback();//出现异常回滚事务
throw new RuntimeException(e.getMessage(), e);
} finally {
HibernateUtil.closeSession();
}
}
===========================================
说明:关于getCurrentSession()方法:
sessionFactory.getCurrentSession()获取当前线程中的Session, 当调用时,hibernate将session绑定到当前线程,事务结束后,hibernate将session从当前线程中释放,并且关闭 session。当再次调用getCurrentSession()时,将得到一个新的session,并重新开始这一系列工作。这样调用方法如下: Session session = HibernateUtil.getSessionFactory().getCurrentSession();
getCurrentSession和openSession的区别:
1、getCurrentSession创建的session会和绑定到当前线程,而openSession不会。
2、getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭
3、getCurrentSession需在在Hibernate.cfg.xml文件中添加配置:
<property name="current_session_context_class">thread</property>
四、总结
这种解决方案的优缺点:
1. 优点:使用ThreadLocal除了有避免频繁创建和销毁session的好处外, 还有一个特别大的好处,
就是可以做到多线程的数据隔离, 可以避免多个线程同时操作同一个session
2. 缺点: 如下图
使用拦截器在响应返回时,又重复过滤了一次,延长了响应的时间(改进:我们可以把写在过滤器中的方法写在一个具体的类,用到的时候再调用)
五:注意:
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。
1. synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。
2. ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
Hibernate学习笔记--使用ThreadLocal的更多相关文章
- Hibernate学习笔记(二)
2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...
- Hibernate学习笔记(一)
2016/4/18 19:58:58 Hibernate学习笔记(一) 1.Hibernate框架的概述: 就是一个持久层的ORM框架. ORM:对象关系映射.将Java中实体对象与关系型数据库中表建 ...
- Hibernate 学习笔记一
Hibernate 学习笔记一 今天学习了hibernate的一点入门知识,主要是配置domain对象和表的关系映射,hibernate的一些常用的配置,以及对应的一个向数据库插入数据的小例子.期间碰 ...
- Hibernate学习笔记-Hibernate HQL查询
Session是持久层操作的基础,相当于JDBC中的Connection,通过Session会话来保存.更新.查找数据.session是Hibernate运作的中心,对象的生命周期.事务的管理.数据库 ...
- 并发编程学习笔记(8)----ThreadLocal的使用及源码分析
1. ThreadLocal的理解 ThreadLocal,顾名思义,就是线程的本地变量,ThreadLocal会为每个线程创建一个本地变量副本,使得使用ThreadLocal管理的变量在多线程的环境 ...
- SpringMVC:学习笔记(12)——ThreadLocal实现会话共享
SpringMVC:学习笔记(12)——ThreadLocal实现会话共享 ThreadLocal ThreadLocal,被称为线程局部变量.在并发编程的情况下,使用ThreadLocal创建的变量 ...
- Hibernate学习笔记
一.Hibernate基础 1.Hibernate简介 Hibernate是一种对象关系映射(ORM)框架,是实现持久化存储的一种解决方案.Java包括Java类到数据库表的映射和数据查询及获取的方法 ...
- Hibernate学习笔记一
1 框架体系结构 2 hibernate入门 2.1 ORM框架 Hibernate是一个数据持久化层的ORM框架. Object:对象,java对象,此处特指JavaBean Relational: ...
- Hibernate学习笔记(三)—— Hibernate的事务控制
Hibernate是对JDBC的轻量级封装,其主要功能是操作数据库.在操作数据库过程中,经常会遇到事务处理的问题,接下来就来介绍Hibernate中的事务管理. 在学习Hibernate中的事务处理之 ...
随机推荐
- DOCKER脚本一例---快速建立大批测试机
这个会由一系列的脚本构成,比如: 系统重启后,如何快速恢复服务,如何建立网桥(也可一次写入),如何在新系统上快速部署. ADDBRIDGE #!/bin/sh br_name=br100 brctl ...
- 如何关闭Altium Designer联网功能(图文教程)
画PCB电路板的人们都知道Altium Designer这款软件,本文介绍如何避免收到Attorney,关掉Altium Designer 的自动联网功能,需要两步,介绍如下 打开AD软件, DXP- ...
- HDOJ 1335 Basically Speaking(进制转换)
Problem Description The Really Neato Calculator Company, Inc. has recently hired your team to help d ...
- hdu-1800
思路: 这题被坑的不轻. 首先花了一段时间想明白了思路是要找出现次数最多数字,以为这题就这样解决了,结果发现每个数字的最大长度是30,long long都装不下,因此就要用字符串来保存处理.然后在in ...
- 批量将文件转换为UTF-8无BOM格式
最近有一个项目需要迁移,要把文件全部转换成utf8格式的,本来想用python,后来听说PowerShell很是强大,就试着用了一下,果然好用啊! $list = Get-ChildItem .\ - ...
- MD中bitmap源代码分析--状态机实例
1. page_attrs的状态转换关系 之前说过,bitmap的优化核心是:bitmap设置后批量写入:bitmap延时清除.写bit用bitmap_statrwrite() + bitmap_un ...
- hadoop2.2.0的ha分布式集群搭建
hadoop2.2.0 ha集群搭建 使用的文件如下: jdk-6u45-linux-x64.bin hadoop-2.2.0.x86_64.tar zookeeper-3.4.5. ...
- WingIDE注册破解方法
WingIDE是Python程序语言设计的集成开发环境,具有语法标签高亮显示,命令自动完成和函数跳转列表等非常强大的功能.本文主要介绍WingIDE 5安装及注册破解方法. 1. WingIDE 5下 ...
- SD卡中FAT32文件格式高速入门(图文具体介绍)
说明: MBR :Master Boot Record ( 主引导记录) DBR :DOS Boot Record ( 引导扇区) FAT :File Allocation Table ( 文件分配表 ...
- Java和C#中String直接赋值与使用new创建(==与equals进行比较)的区别
在Java中,字符串可以直接赋值或者使用new来新建,直接赋值的话是编译阶段(.class文件)中就将该字符串值放到常量池中,以后如果有其他变量直接赋予同样的值的话就不再分配内存空间,而是直接给它个引 ...