详解Hibernate Session & Transaction
- 格式:docx
- 大小:24.30 KB
- 文档页数:12
hibernate深度学习游离状态HQL当我学完这个之后我仿佛都懂了 = =或许这就是 hibernate的⼒量吧.操纵持久化对象(Session)1.1. 在hibernate中java对象的状态Hibernate 把对象分为 4 种状态:¨ 持久化状态,¨ 临时状态,¨ 游离状态,¨ 删除状态.Session 的特定⽅法能使对象从⼀个状态转换到另⼀个状态1.2. 临时对象(transient)¨ 在使⽤代理主键的情况下, OID 通常为 null¨ 不处于 Session 的缓存中¨ 在数据库中没有对应的记录1.2.1. 删除对象(Removed)¨ OID 不为 null¨ 从⼀个 Session实例的缓存中删除¨ Session 已经计划将其从数据库删除, Session 在清理缓存时, 会执⾏ SQL delete 语句, 删除数据库中的对应记录¨ ⼀般情况下, 应⽤程序不该再使⽤被删除的对象1.2.2. 持久化对象(也叫”托管”)(Persist)1.2.3.¨ OID 不为 null¨ 位于 Session 缓存中¨ 持久化对象和数据库中的相关记录对应¨ Session 在清理缓存时, 会根据持久化对象的属性变化, 来同步更新数据库¨ 在同⼀个 Session 实例的缓存中, 数据库表中的每条记录只对应唯⼀的持久化对象1.2.4. 游离对象(也叫”脱管”)(Detached)¨ OID 不为 null¨ 不再处于 Session 的缓存中¨ ⼀般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录1.2.5. 对象的状态转换说明(图)对象的状态转换图测试hibernate中java对象的状态程序代码⽣命周期状态tx = session.beginTransaction();开始⽣命周期临时状态Customer c = new Customer);Session.save(c)处于⽣命周期中转变为持久化状态Long id=c.getId();处于⽣命周期中处于持久化状态c = null;Customer c2 =(Customer)session.load(Customer.class,id);mit();session.close();处于⽣命周期中转变为游离态c2.getName();处于⽣命周期中处于游离态c2 = null;结束⽣命周期结束⽣命周期1.2.6. 对象的状态总结Session缓存存在对应的记录数据中存在对应的记录临时态no no持久态yes可能有也可能没有游离态no可能有(数据没有删除)也可能没有1.2.7. 操纵持久化对象的⽅法(Session中)1.2.8. save()Session 的 save() ⽅法使⼀个临时对象转变为持久化对象。
hibernate框架的工作原理Hibernate框架的工作原理Hibernate是一个开源的ORM(Object-Relational Mapping)框架,它将Java对象映射到关系型数据库中。
它提供了一种简单的方式来处理数据持久化,同时也提供了一些高级特性来优化性能和可维护性。
1. Hibernate框架的基本概念在开始讲解Hibernate框架的工作原理之前,需要先了解一些基本概念:Session:Session是Hibernate与数据库交互的核心接口,它代表了一个会话,可以用来执行各种数据库操作。
SessionFactory:SessionFactory是一个线程安全的对象,它用于创建Session对象。
通常情况下,应用程序只需要创建一个SessionFactory对象。
Transaction:Transaction是对数据库操作进行事务管理的接口。
在Hibernate中,所有对数据库的操作都应该在事务中进行。
Mapping文件:Mapping文件用于描述Java类与数据库表之间的映射关系。
它定义了Java类属性与数据库表字段之间的对应关系。
2. Hibernate框架的工作流程Hibernate框架主要分为两个部分:持久化层和业务逻辑层。
其中,持久化层负责将Java对象映射到数据库中,并提供数据访问接口;业务逻辑层则负责处理业务逻辑,并调用持久化层进行数据访问。
Hibernate框架的工作流程如下:2.1 创建SessionFactory对象在应用程序启动时,需要创建一个SessionFactory对象。
SessionFactory是一个线程安全的对象,通常情况下只需要创建一个即可。
2.2 创建Session对象在业务逻辑层需要进行数据访问时,需要先创建一个Session对象。
Session是Hibernate与数据库交互的核心接口,它代表了一个会话,可以用来执行各种数据库操作。
2.3 执行数据库操作在获取了Session对象之后,就可以执行各种数据库操作了。
主要讨论Spring与Hibernate集成中的session问题1.通过getSession()方法获得session进行操作Java代码利用这种方式获得的session在方法执行结束之后不会自动关闭连接,也就是说我们必须通过session.close()或者releaseSession(session)来手动进行关闭,否则会造成内存泄露或者连接耗尽等问题。
手动关闭:Java代码如果对上述方法进行事务控制,那么spring框架会自动为我们关闭session,此种情况下再执行上述代码,会抛出如下异常:Java代码提示session已经关闭。
但是如果在代码中通过releaseSession(session)的方法来关闭session,则不会抛出异常。
releaseSession(session)方法的代码如下:Java代码也就是说它是通过SessionFactoryUtils的releaseSession方法来实现的:Java代码可见它内部会先进行判断。
查看getSession()方法的源码:Java代码getSession()方法内部通过它的一个重载方法getSession(boolean allowCreate )来实现,变量allowCreate是HibernateTemplate中的变量,默认值为true,也就是创建一个新的session。
如果我们调用getSession(false)来获得session,那么必须对其进行事务控制,原因是:(spring文档)Java代码也就是说,getSession()方法从当前事务或者一个新的事务中获得session,如果想从一个新的事务中获得session(也就意味着当其不存在事务控制),则必须使HibernateTemplate中的allowCreate变量的值为”true”,而现在设置allowCreate变量的值为”false”就意味着无法从新的事务中获得session,也就是只能从当前事务中获取,所以必须对当前方法进行事务控制,否则会抛出如下异常:Java代码同时,如果对getSession()所在的方法进行事务控制,那么类似如下的代码:只会打开一个session,因为事务控制必须确保是同一个连接,spring会确保在整个相关方法中只存在一个session。
Hibernate查询首先介绍get()和load()方法的区别:get()方法和load()方法的区别主要在于对二级缓存的使用上。
load()方法会使用二级缓存,而get()方法在一级缓存没有找到会直接查询数据库,不会去二级缓存中查找。
get():如果在数据库中没有记录会返回空,get()无论如何都会返回数据.load():如果数据库中没有记录会抛出异常,如果有数据返回的是一个代理对象。
list和iterator()方法之间的区别:(N+1?)list()方法在执行时,直接运行查询结果所需要的查询语句。
iterator()方法则是先执行得到对象ID的查询,然后在根据每个ID值去取得所要查询的对象。
因此:对于list()方式的查询通常只会执行一个SQL语句,而对于iterator()方法的查询则可能需要执行N+1条SQL语句(N为结果集中的记录数).结果集的处理方法不同:list()方法会一次活的所有的结果集对象,而且他会依据查询的结果初始化所有的结果集对象。
如果在结果集非常庞大的时候会占据非常多的内存,甚至会造成内存溢出的情况发生。
iterator()方法在执行时不会一次初始化所有的对象,而是根据对结果集的访问情况来初始化对象。
一次在访问中可以控制缓存中对象的数量,以避免占用过多的缓存,导致内存溢出情况的发生。
HQL:HQL是一种面向对象的查询语言,HQL的操作对象是类、实例和属性等。
SQL:sql的操作对象是数据表和列等数据对象。
Hql是完全面向对象的查询语言,因此可以支持继承和多条等特征。
HQL查询依赖于Query类,每个Query实例对应一个查询对象。
定参数的功能,Query 接口才是真正的HQL查询接口。
//创建一个Query 对象Java代码1Query query = session.createQuery ("from Customer as c where=:customerName and c.age=:customerAge");//动态绑定参数Java代码2query.setString("customerName","Tom");3query.setInteger("customerAge",21);//执行查询语句,返回结果Java代码4List result = query.list();HQL查询步骤:1:获取Hibernate Session对象。
简述hibernate查询数据库的步骤Hibernate是一个开源的Java持久化框架,它可以帮助开发者简化数据库操作,提高开发效率。
在Hibernate中,查询数据库是非常常见的操作,本文将以标题的方式,简述Hibernate查询数据库的步骤。
一、配置Hibernate在开始使用Hibernate查询数据库之前,首先需要进行Hibernate 的配置工作。
包括创建Hibernate配置文件(hibernate.cfg.xml),配置数据库连接信息、数据库方言等。
同时,还需要配置实体类与数据库表之间的映射关系(Hibernate映射文件)。
二、创建SessionFactorySessionFactory是Hibernate的核心接口之一,它负责创建Session对象,是实现Hibernate查询的基础。
在Hibernate中,SessionFactory是线程安全的,通常一个应用程序只需要一个SessionFactory实例。
三、打开Session在进行数据库查询之前,需要先打开一个Session。
Session是Hibernate中的一个重要概念,它代表一个与数据库的会话。
可以通过SessionFactory的openSession方法来打开一个Session。
四、开始事务在进行数据库查询操作之前,通常需要开启一个事务。
通过调用Session的beginTransaction方法,开始一个事务。
事务的开启可以保证数据的一致性和完整性。
五、执行查询操作在Hibernate中,有多种查询方式可以选择。
常见的查询方式包括HQL查询、QBC查询和Native SQL查询。
HQL(Hibernate Query Language)是Hibernate提供的一种面向对象的查询语言,类似于SQL语句。
QBC(Criteria Query)是一种基于Criteria的查询方式,可以通过CriteriaBuilder来构建查询条件。
在各种Session 管理方案中,ThreadLocal 模式得到了大量使用。
ThreadLocal 是Java 中一种较为特殊的线程绑定机制。
通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。
首先,我们需要知道,SessionFactory负责创建Session,SessionFactory是线程安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session 实例。
而Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,则将会导致Session 数据存取逻辑混乱。
下面是一个典型的Servlet,我们试图通过一个类变量session实现Session的重用,以避免每次操作都要重新创建:public class TestServlet extends HttpServlet {private Session session;public void doGet( HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {session = getSession();doSomething();session.flush();}public void doSomething(){......//基于session的存取操作}}代码看上去正确无误,甚至在我们单机测试的时候可能也不会发生什么问题,但这样的代Hibernate Developer's Guide Version 1.0September 2, 2004 So many open source projects. Why not Open your Documents?码一旦编译部署到实际运行环境中,接踵而来的莫名其妙的错误很可能会使得我们摸不找头脑。
hibernate createnativequery 使用-回复Hibernate CreateNativeQuery 使用指导Hibernate是一个流行的Java持久化框架,它提供了一种方便的方式来将对象模型映射到关系数据库中。
除了支持HQL(Hibernate Query Language)查询,Hibernate还允许开发人员直接执行原生的SQL查询。
这对于在特定情况下需要执行复杂查询或优化性能时非常有用。
本文将介绍Hibernate的CreateNativeQuery方法的使用,一步一步地回答常见的问题。
什么是CreateNativeQuery?CreateNativeQuery是Hibernate的一个方法,它允许开发人员执行原生的SQL查询。
它接受一个SQL查询字符串作为参数,并返回一个NativeQuery对象,可以使用该对象来执行查询并获取结果。
如何使用CreateNativeQuery?以下是使用CreateNativeQuery的基本步骤:步骤1: 获取Hibernate Session要执行SQL查询,首先需要通过Hibernate获取一个Session对象。
Session是Hibernate的核心接口之一,它表示与数据库的连接和数据读写操作。
例子:javaSession session = HibernateSessionFactory.getSession();步骤2: 创建原生SQL查询使用session对象的CreateNativeQuery方法来创建一个NativeQuery 对象。
该方法接受一个SQL查询字符串作为参数。
例子:javaString sql = "SELECT * FROM users WHERE age > :age"; NativeQuery<User> query = session.createNativeQuery(sql, User.class);在上面的例子中,我们创建了一个查询,用于选择年龄大于给定参数age的用户。
Hibernate工作原理及为什么要用?一原理:1.读取并解析配置文件2.读取并解析映射信息,创建SessionFactory3.打开Sesssion4.创建事务Transaction5.持久化操作6.提交事务7.关闭Session。
8.关闭SessionFactory为什么要用:1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。
他很大程度的简化DAO层的编码工作3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4. hibernate的性能非常好,因为它是个轻量级框架。
映射的灵活性很出色。
它支持各种关系数据库,从一对一到多对多的各种复杂关系。
二Hibernate 的核心接口及其作用1 Configuration类:配置Hibernate启动Hibernate创建SessionFactory对象2 SessionFactory:初始化Hibernate创建Session对象线程安全—同一实例被多个线程共享重量级:代表一个数据库内部维护一个连接池2.1 openSession():总是创建新的session,需要手动close()2.2 getCurrentSession() : 必须在hibernate.cfg.xml设置session 上下文事务自动提交并且自动关闭session.从上下文环境中获得session,如果当时环境中不存就创建新的.如果环境中存在就使用环境中的,而且每次得到的都是同一个session (在session提交之前,提交之后就是新的了) 应用在一个session中有多个不同DAO操作处于一个事务时3 Session:负责保存、更新、删除、加载和查询对象轻量级--可以经常创建或销毁3.1 Load与get方法的区别:简单理解:load是懒加载,get是立即加载.load方法当使用查出来的对象时并且session未关闭,才会向数据库发sql, get会立即向数据库发sql返回对象3.3 merge(); 合并对象更新前会先select 再更新3.4clear()清空缓存,flush()将session中的数据同步到数据库两者组合使用于批量数据处理3.4Transaction commit() rollback()JPA: java persistence API 提供了一组操作实体bean的注解和API规范SchemaExporthiberante的生成数据库表(及其他ddl)的工具类可以通过这个工具类完成一些ddl四Hibernate查询查询语言主要有:HQL 、QBC (Query By Criteria条件查询) 、 Native SQLHql:1、属性查询2、参数查询、命名参数查询3、关联查询4、分页查询5、统计函数五优化抓取策略连接抓取(Join fetching)使用 OUTER JOIN(外连接)来获得对象的关联实例或者关联集合查询抓取(Select fetching)另外发送一条 SELECT 语句抓取当前对象的关联实体或集合另外可以配置hibernate抓取数量限制批量抓取(Batch fetching)另外可以通过集合过滤来限制集合中的数据量使用session.createFilter(topic.getReplies(),queryString).list();检索策略延迟检索和立即检索(优先考虑延迟检索)N+1问题指hibernate在查询当前对象时查询相关联的对象查询一端时会查询关联的多端集合对象解决方案:延迟加载连接抓取策略二级缓存集合过滤 BatchSize限制记录数量映射建议使用双向一对多关联,不使用单向一对多灵活使用单向一对多关联不用一对一,用多对一取代配置对象缓存,不使用集合缓存一对多集合使用Bag,多对多集合使用Set继承类使用显式多态表字段要少,表关联不要怕多,有二级缓存撑腰Hibernbate缓存机制性能提升的主要手段Hibernate进行查询时总是先在缓存中进行查询,如缓存中没有所需数据才进行数据库的查询.Hibernbate缓存:一级缓存 (Session级别)二级缓存(SessionFactory级别)查询缓存 (基于二级缓存存储相同参数的sql查询结果集)一级缓存(session缓存)Session缓存可以理解为session中的一个map成员, key为OID ,value为持久化对象的引用在session关闭前,如果要获取记录,hiberntae先在session缓存中查找,找到后直接返回,缓存中没有才向数据库发送sql三种状态的区别在于:对象在内存、数据库、session缓存三者中是否有OID临时状态内存中的对象没有OID, 缓存中没有OID,数据库中也没有OID 执行new或delete()后持久化状态内存中的对象有OID, 缓存中有OID,数据库中有OIDsave() load() get() update() saveOrUpdate() Query对象返回的集合游离(脱管)状态内存中的对象有OID, 缓存中没有OID,数据库中可能有OIDflush() close()后使用session缓存涉及三个操作:1将数据放入缓存2从缓存中获取数据3缓存的数据清理4二级缓存SessionFactory级别SessionFactory级别的缓存,它允许多个Session间共享缓存一般需要使用第三方的缓存组件,如: Ehcache Oscache、JbossCache等二级缓存的工作原理:在执行各种条件查询时,如果所获得的结果集为实体对象的集合,那么就会把所有的数据对象根据OID放入到二级缓存中。
实验10 hibernate session操作一、Department 有三个字段(id,name,number,leadid);name为部门名称,number为部门人数,leadid为负责人id要求1name字段必须为中文。
要求2. 完成Department的增加、删除、修改操作中文乱码的修改过程二、新建person表格(id,name,age);其中Department 中的leadid是外键,对应person表中的主键。
Department 有三个字段(id,name,number,leadid);name为部门名称,number为部门人数,leadid为负责人id1.设置主外键2.实现联合添加。
course表中CONSTRAINT `FK_stuid` FOREIGN KEY (`stuid`) REFERENCES `student` (`id`)下节课讲解HQL实验9 hibernate 入门实验(p185)employee有三个字段(id,name,pass)id为主键实现数据库添加效果,表名小写1、显示DB Browserjdbc:mysql://localhsot:3306/数据库名称点test Driver 后测试成功2、加载hibernate能力注意和新建的DB Browser 名字要一致3、逆向生产注意:其他地方不要钩自动生产以下文件:Employee有三个字段(id,name,pass)实现数据库添加效果在<mapping resource="po/User.hbm.xml" />hibernate.cfg.xml二、文件上传:二、文件上传:。
详解Hibernate Session & Transaction2011-04-06 19:32:27| 分类:JavaEE | 标签:session线程hibernate实例transaction |字号订阅HIbernate中的SessionSession是JAVA应用程序和Hibernate进行交互时使用的主要接口,它也是持久化操作核心API,注意这里的Session的含义,它与传统意思上web层的HttpSession并没有关系,Hibernate Session之与Hibernate,相当于JDBC Connection相对与JDBC。
Session对象是有生命周期的,它以Transaction对象的事务开始和结束边界Session作为贯穿Hibernate的持久化管理器核心,提供了众多的持久化的方法,如save(), update ,delete ,find(Hibernate 3中已经取消了此方法)等,通过这些方法我们可以透明的完成对象的增删改查(CRUD-- create read update delete),这里所谓的透明是指,Session在读取,创建和删除影射的实体对象的实例时,这一系列的操作将被转换为对数据库表中数据的增加,修改,查询和删除操作。
SessionFactory负责创建Session,SessionFactory是线程安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session实例。
而Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,则将会导致Session 数据存取逻辑混乱.因此创建的Session实例必须在本地存取空上运行,使之总与当前的线程相关。
Session有以下的特点1,不是线程安全的,应该避免多个线程共享同一个Session实例2,Session实例是轻量级的,所谓轻量级:是指他的创建和删除不需要消耗太多资源3,Session对象内部有一个缓存,被称为Hibernate第一缓存,他存放被当前工作单元中加载的对象,每个Session实例都有自己的缓存。
Hibernate Session缓存被称为Hibernate的第一级缓存。
SessionFactory的外置缓存称为Hibernate的二级缓存。
这两个缓存都位于持久层,它们存放的都是数据库数据的拷贝。
SessionFactory的内置缓存存放元数据和预定义SQL,SessionFactory的内置缓存是只读缓存。
Hibernate Session缓存的三大作用:1,减少数据库的访问频率,提高访问性能。
2,保证缓存中的对象与数据库同步,位于缓存中的对象称为持久化对象。
3,当持久化对象之间存在关联时,Session 保证不出现对象图的死锁。
Session 如何判断持久化对象的状态的改变呢?Session 加载对象后会为对象值类型的属性复制一份快照。
当Session 清理缓存时,比较当前对象和它的快照就可以知道那些属性发生了变化。
Session 什么时候清理缓存?1,commit()方法被调用时2,查询时会清理缓存,保证查询结果能反映对象的最新状态。
3,显示的调用session 的 flush方法。
session 清理缓存的特例:当对象使用 native 生成器时会立刻清理缓存向数据库中插入记录。
org.hibernate Interface Sessionpublic interface Session extends Serializable : 是一个Java application 和Hibernate之间主要的运行时接口,这是执行持久化服务的中心API主要方法:public Transaction beginTransaction() throws HibernateException【1】:返回和当前Session对象相互联系的Transaction对象(表示在数据库中重新开始一个事务)public Transaction getTransaction():返回和当前session联系的Transaction对象public Connection connection close() throws HibernateExcepton:结束当前的Session对象public void clear() :清空Session,清除所有保存在当前Session缓存中的实体对象,终止所有正在执行的方法(eg: save() ,update() ,delete() .....)public Serializable save(Object object)throws HibernateException 对当前参数指定的对象进行持久化(系统会首先赋予参数对象一个标识符OID),他相当于insert语句后面在详细介绍public Connection connection() throws HibernateException 得到当前Session 中包含的Connection对象。
public boolean contains(Object object):判断参数给出的对象(持久化类)是否在当前Session的缓存中public void evict(Object object) throws HibernateException :将参数给出的Object从当前Session对象类中删除,使这个对象从持久态变成游离态,这种状态的改变不会引起对数据库的同步,后面详细介绍public Object load(Class theclass ,Serializable id) throws HibernateException 返回第一个参数指定类对应的表中,第二个参数指定的行(第二个参数就是要取得对象的OID,他对应表中主键列的值)public void update(Object object) throws HibernateException :更新一个对象到数据库中,后面在详细介绍public void delete (Object object)throws HibernateException:从数据库中删除和参数指定的对象对应的记录public Object get(Class class,Serializable id) throwsHibernateException:和load()方法一样区别在于,如果数据库表中没有对应的记录,get()方法返回null,load()方法将报异常TransactionTransanction 接口是Hibernate的数据库事务接口,用于管理事务,他对底层的事务作出了封装,用户可以使用Transanction对象定义自己的对数据库的原子操作,底层事务包括:JDBC API ,JTA(Java Transaction API)。
一个Transaction对象的事务可能会包括多个对数据库进行的操作org.hibernate Interface Transactionpublic interface Transaction常用方法:public void commit() throws HibernateException 刷新当前的Session 以及结束事务的工作,这个方法将迫使数据库对当前的事务进行提交public void rollback() throws HibernateException :强迫回滚当前事务public boolean isActive() throws HibernateException:这个事务是否存活----------------------------------------------------------------------------------------Session:当中包含一个Connection对象Connection c =session.getConnection();Session的缓存用于临时保存持久化的对象,等到一定时候,再将缓存中的对象保存到数据库中。
应用程序事务:如果一个Session中包含有多个Transaction(数据库事务),这些Transaction的集合称为应用程序事务标准使用形式:Configuration config=newConfiguration().configure("hibernate.cfg.xml");SessionFactory sessionfactory=config.buildSessionFactory();Session session=sessionfactory.openSession();Transaction tx=session.beginTransaction();try{session.save();mit();}catch(Exception e){if(tx!=null) tx.rollback();}finally{session.close ();}保证session的线程安全ThreadLocal,在很多种Session 管理方案中都用到了它.ThreadLocal 是Java 中一种较为特殊的线程绑定机制,通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制,ThreadLocal并不是线程本地化的实现,而是线程局部变量。
也就是说每个使用该变量的线程都必须为该变量提供一个副本,每个线程改变该变量的值仅仅是改变该副本的值,而不会影响其他线程的该变量的值,ThreadLocal是隔离多个线程的数据共享,不存在多个线程之间共享资源,因此不再需要对线程同步。
请看一下代码:public class HibernateUtil {public static final SessionFactory sessionFactory;public static final ThreadLocal session = new ThreadLocal();static{try{Configuration configuration=new Configuration().configure(); sessionFactory = configuration.buildSessionFactory();}catch (Throwable ex){System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex);}}public static Session currentSession() throws HibernateException{ Session s = (Session) session.get();if (s == null){s = sessionFactory.openSession();session.set(s);}return s;}public static void closeSession() throws HibernateException { Session s = (Session) session.get();if (s != null)s.close();session.set(null);}}不安全解释,例如:Servlet 运行是多线程的,而应用服务器并不会为每个线程都创建一个Servlet实例,也就是说,TestServlet在应用服务器中只有一个实例(在Tomcat中是这样,其他的应用服务器可能有不同的实现),而这个实例会被许多个线程并发调用,doGet 方法也将被不同的线程反复调用,可想而知,每次调用doGet 方法,这个唯一的TestServlet 实例的session 变量都会被重置在代码中,只要借助上面这个工具类获取Session 实例,我们就可以实现线程范围内的Session 共享,从而避免了在线程中频繁的创建和销毁Session 实例。