文档章节

Hibernate<二> - Session

PythonJsGo
 PythonJsGo
发布于 2017/08/17 10:28
字数 2656
阅读 18
收藏 2

#程序员薪资揭榜#你做程序员几年了?月薪多少?发量还在么?>>>

1、Session概述

    Session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存更新删除加载Java对象的方法。

    每一个Session对象都在内存中维护了一个缓存,位于缓存中的对象称为持久化对象,它和数据库表中的相关记录保持着一种对应关系。通过Session缓存,Hibernate最大限度的减少了应用程序访问数据库的次数,实现了对内存空间更加有效的利用。

    Hibernate把持久化类的对象分为4种状态:持久化状态临时状态游离状态删除状态。Session的特定方法能使对象从一个状态转换到另一个状态。

2、Session缓存

    在应用系统开发过程中,使用缓存往往是提升程序性能的主要手段。在Hibernate中,Session对象维护的是一个线程级的一级缓存,SessionFactory维护了一个进程级别的二级缓存。二级缓存会在后面的博客中详细介绍,现在先关注Session维护的一级缓存。

    2.1  使用Session缓存的好处

        ①减少访问数据库的次数

        两次调用session.get(Student.class,1);方法,仅发送1条SQL语句。原因是第一次使用get()方法加载的Student被缓存到了内存中,第二次调用get()方法直接使用了内存中缓存的Student对象,从而减少了访问数据库的次数

    Tips:应用程序中访问数据库的次数往往是最主要的性能瓶颈。

        ②将内存中数据的变化自动同步到数据库中

    使用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/  

© 著作权归作者所有

PythonJsGo
粉丝 33
博文 116
码字总数 184446
作品 0
朝阳
高级程序员
私信 提问
加载中

评论(0)

Java之Hibernate常见面试题

  Java之Hibernate常见面试题   1、hibernate的inverse属性的作用?   解决方案一,按照Object[]数据取出数据,然后自己组bean   解决方案二,对每个表的bean写构造函数,比如表一要查...

好程序员
2019/10/29
0
0
Hibernate openSession() 与 getCurrentSession() 区别

一、getCurrentSession()与openSession()的区别 1、getCurrentSession () 使用当前的session openSession() 重新建立一个新的session 2、采用getCurrentSession()创建的session会绑定到当前线...

LYQ1990
2016/04/27
86
0
简单理解Hibernate三种状态的概念及互相转化

本文描述了Hibernate三种状态的概念及互相转化。Java对象的生命周期中有三种状态,而且互相转化。它们分别是临时状态,持久化状态,以及游离状态。 AD:51CTO学院:IT精品课程在线看! 在Hib...

xiaml
2014/03/30
107
0
MyBatis原理简介和小试牛刀

在我看来mybatis的原理与hibernate在某些方面是一致的,先回顾一下Hibernate原理(原理主要上是要掌握并理解下列六个对象: Hibernate中重要的六个对象: Configuration:读取配置文件(主要指h...

youcongtech
2017/11/18
0
0
Hibernater学习笔记(三)

1.Hibernate缓存 Hibernate一级缓存 hibernate 的一级缓存默认是打开的 hibernate的一级缓存使用范围,是session范围,从session创建到session关闭范围 hibernate的一级缓存中,储存数据必须...

Mr_欢先生
2017/12/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

C# 数据操作系列 - 19 FreeSql 入坑介绍

0. 前言 前几天FreeSql的作者向我推荐了FreeSql框架,想让我帮忙写个文章介绍一下。嗯,想不到我也能带个货了。哈哈,开个玩笑~看了下觉得设计的挺有意思的,所以就谢了这篇文章。 简单介绍...

osc_nreg1aho
8分钟前
10
0
怎么查看CAD?多角度、多维度快速看图,选这款CAD编辑器就对了

怎么查看CAD文件呢?想要多角度、多维度快速查看CAD图纸文件,小伙伴们选择这款CAD编辑器就对啦。小伙伴们都知道,想要打开、查看DXF、DWG格式的文件,需要借助专门的CAD编辑器软件工具。而很...

深蓝月上
10分钟前
5
0
使用PInvoke互操作,让C#和C++愉快的交互优势互补

一:背景 1. 讲故事 如果你常翻看FCL的源码,你会发现这里面有不少方法借助了C/C++的力量让C#更快更强悍,如下所示: [DllImport("QCall", CharSet = CharSet.Unicode)][SecurityCritical...

osc_tjee7sjs
10分钟前
5
0
在vue的filter中显示html

显示温度时要同时体现这个温度值是否正常,可以通过过滤器实现,步骤如下: 添加过滤器 export function toTemperature(value) { if (value > 500 || value < -500) { return '<span ......

不再熬夜
10分钟前
5
0
阿里云服务器无法访问80或8080端口的

新购买的阿里云服务器,配置好后,localhost是可以正常访问项目的,但是无法从外网访问,这就说明端口被禁止访问了。解决此问题的方法如下: 1、登录阿里云的管理控制台,找到实例: 2、在实...

osc_vb3phyau
11分钟前
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部