一、Session概述java
Session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存、更新、删除和加载Java对象的方法。git
每个Session对象都在内存中维护了一个缓存,位于缓存中的对象称为持久化对象,它和数据库表中的相关记录保持着一种对应关系。经过Session缓存,Hibernate最大限度的减小了应用程序访问数据库的次数,实现了对内存空间更加有效的利用。github
Hibernate把持久化类的对象分为4种状态:持久化状态、临时状态、游离状态、删除状态。Session的特定方法能使对象从一个状态转换到另外一个状态。数据库
二、Session缓存缓存
在应用系统开发过程当中,使用缓存每每是提高程序性能的主要手段。在Hibernate中,Session对象维护的是一个线程级的一级缓存,SessionFactory维护了一个进程级别的二级缓存。二级缓存会在后面的博客中详细介绍,如今先关注Session维护的一级缓存。session
2.1 使用Session缓存的好处并发
①减小访问数据库的次数ide
两次调用session.get(Student.class,1);方法,仅发送1条SQL语句。缘由是第一次使用get()方法加载的Student被缓存到了内存中,第二次调用get()方法直接使用了内存中缓存的Student对象,从而减小了访问数据库的次数。性能
Tips:应用程序中访问数据库的次数每每是最主要的性能瓶颈。hibernate
②将内存中数据的变化自动同步到数据库中
使用session.get(Student.class,1);方法将一个Student对象加载到内存中后,Student对象就处于Session对象的管理中。此时调用student.setStuName(“a”);方法将触发Hibernate对数据库表中对应数据记录的修改,即发送一条UPDATE语句,更新Student对象在数据库表中对应的记录。
Hibernate最大的特色就是将对数据库记录的操做,转换为对Java对象的操做,简化开发。
2.2 Session缓存操做概述
①flush:推送。将缓存中数据的改变落实到数据库中
②refresh:刷新。将数据库中数据的改变提取到缓存中
③clear:清空。清空Session缓存
2.3 flush操做
①Session对象默认在什么状况下执行flush操做?
②默认状况下Session执行flush操做的时机:
[1]显式调用Session的flush()方法
[2]调用Transaction对象的commit()方法时,先flush缓存,在提交事务
[3]执行HQL、QBC查询以前,先flush缓存,保证HQL或QBC查询到的数据是最新的。
③相关问题
[1]修改持久化对象的属性值,并不会当即发送SQL语句,而是提交事务以前,执行flush操做的时候才会发送相应的UPDATE语句。
[2]发送UPDATE语句时,数据的修改并不会当即生效,只有提交了事务以后,数据的修改才会永久的保存下来。
2.4 refresh操做与事务隔离级别
①提出问题
在使用MySQL客户端修改数据后,refresh()方法读取到的仍是旧的未修改的数据,为何?
②分析
MySQL默认的数据库事务隔离级别是“可重复读”,要保证当前事务执行期间的不一样时间点读取到的数据是同样的。
③结论
refresh()方法读取到的数据是否是真正的最新数据,须要参照当前的事务隔离级别。
3 事务隔离级别回顾
3.1 数据库事务并发问题
假设如今有两个事务:Transaction01和Transaction02并发执行。
①脏读
[1]Transaction01将某条记录的AGE值从20修改成30。
[2]Transaction02读取了Transaction01更新后的值:30。
[3]Transaction01回滚,AGE值恢复到了20。
[4]Transaction02读取到的30就是一个无效的值。
②不可重复读
[1]Transaction01读取了AGE值为20。
[2]Transaction02将AGE值修改成30。
[3]Transaction01再次读取AGE值为30,和第一次读取不一致。
③幻读
[1]Transaction01读取了STUDENT表中的一部分数据。
[2]Transaction02向STUDENT表中插入了新的行。
[3]Transaction01读取了STUDENT表时,多出了一些行。
3.2 隔离级别
数据库系统必须具备隔离并发运行各个事务的能力,使它们不会相互影响,避免各类并发问题。一个事务与其余事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不一样隔离级别对应不一样的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
①读未提交:READ UNCOMMITTED
容许Transaction01读取Transaction02未提交的修改。
②读已提交:READ COMMITTED
要求Transaction01只能读取Transaction02已提交的修改。
③可重复读:REPEATABLE READ
确保Transaction01能够屡次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
④串行化:SERIALIZABLE
确保Transaction01能够屡次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操做。能够避免任何并发问题,但性能十分低下。
⑤各个隔离级别解决并发问题的能力见下表
⑥各类数据库产品对事务隔离级别的支持程度
⑦在MySQL中设置隔离级别
[1]每启动一个MySQL程序,就会得到一个单独的数据库链接。每一个数据库链接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。
[2]查看当前的隔离级别:
SELECT @@tx_isolation;
[3]设置当前MySQL链接的隔离级别:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
[4]设置数据库系统的全局的隔离级别:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
⑧在Hibernate中设置隔离级别
[1]JDBC数据库链接使用数据库系统默认的隔离级别。
[2]在Hibernate的配置文件中能够显式的设置隔离级别。每个隔离级别都对应一个整数:
[3]设置方式
<!-- 设置当前数据库事务隔离级别为读已提交 --> <property name="hibernate.connection.isolation">2</property>
4 持久化对象的状态
4.1 四种状态
①临时状态
[1]OID:没有OID。例如:new Student(null, "Kate2015", 18, new Date());
[2]是否在Session缓存中:不在
[3]是否在数据库中有对应的记录:没有
②持久化状态
[1]OID:有OID。例如:Student student = (Student) session.get(Student.class, 1);
[2]是否在Session缓存中:在
[3]是否在数据库中有对应的记录:有
③游离状态
[1]OID:有OID。例如:new Student(1, "Kate2015", 18, new Date());
[2]是否在Session缓存中:不在
[3]是否在数据库中有对应的记录:有
④删除状态
[1]OID:有OID。一般是通过删除操做获得的。
[2]是否在Session缓存中:不在
[3]是否在数据库中有对应的记录:没有
4.2 四种状态之间的转换
5 Session核心方法
5.1 save()
①将一个临时对象转换为持久化对象
②对于OID:忽略临时对象中的“OID”值,save()方法会将数据库产生的新的OID的值赋值给持久化对象
③持久化状态的对象的OID的值是不容许修改的
5.2 persist()
①做用和save()相同
②不容许保存带有OID的对象,会抛异常:org.hibernate.PersistentObjectException
5.3 get()
①根据OID的值,从数据库中当即加载一个对象到内存中。
②若是调用get()方法时,Session缓存中已经有了一个OID相同的对象,则get()方法会将缓存中的对象返回,不发送SQL语句。
5.4 load()
①采用延迟检索策略,在调用load()方法时仅返回一个代理对象,不发送SQL语句。在真正用到非OID属性值时,才发送SQL语句进行查询。
②懒加载初始化异常
[1]全类名:org.hibernate.LazyInitializationException
[2]产生缘由:对一个延迟加载的代理对象进行初始化时,Session缓存中没有对应OID的对象,没法完成初始化。
5.5 update()
①根据游离对象或持久化对象对数据库表进行更新
②update()方法更新一个游离对象时,默认状况下没法获知当前游离对象中的数据和数据库表中的数据是否有差别。因此,不管是否有差别都会发送SQL语句。为了不盲目的发update语句,能够在hbm配置文件的class元素中设置select-before-update属性的值为true。一般不设置这个属性。
③使用update()方法更新一个OID不存在的对象会抛出异常:org.hibernate.StaleObjectStateException
④使用update()方法更新一个游离对象,但此时Session缓存中已经存在了OID相同的持久化对象,会抛出异常:org.hibernate.NonUniqueObjectException
5.6 saveOrUpdate()
①兼具保存和更新两种功能。传入临时对象执行保存,传入游离对象执行更新。
②判断执行INSERT语句仍是UPDATE语句的依据
[1]根据OID的值,若是为null则执行保存,不然执行更新
[2]若是OID的值等于hbm文件中,id元素设置的unsaved-value属性则执行保存操做。
5.7 delete()
①执行删除操做
②删除对象后将OID的值置空:在Hibernate配置文件中加入以下配置
<property name="hibernate.use_identifier_rollback" >true </property>
5.8 doWork()
①用于在Hibernate环境下执行原生的JDBC代码
②示例代码
@Test public void testWork() { session.doWork(new Work() { @Override public void execute(Connection connection) throws SQLException { //使用传入的Connection对象实现原生的JDBC操做... } }); }
GitHub地址:https://github.com/leebingbin/