“Hibernate笔记 4:核心知识”的版本间差异
跳到导航
跳到搜索
(创建页面,内容为“category:Hibernate == 标题文本 ==”) |
(→标题文本) |
||
第1行: | 第1行: | ||
[[category:Hibernate]] | [[category:Hibernate]] | ||
== | == 持久化类的编写规则 == | ||
如果一个 Java 类与数据库表建立了映射关系,那么这个类称为是'''持久化类'''。 (该类有对应的映射文件与数据库表相关联) | |||
编写规则: | |||
# 持久化类衙要提供无'''参数构造方法'''。 | |||
#: 因为在 Hibernate 的底层需要使用反射生成类的实例; | |||
# 持久化类必须:'''属性私有''',且提供'''公有的 get 和 set 方法'''。 | |||
#: 因为在 Hibernate 底 层会将查询到的数据进行封装; | |||
# 持久化类的属性要尽量使用包装类的类型。 | |||
#: 因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更消晰而基本数据类型不容易描述; | |||
# 持久化类要有一个'''唯一标识 OID''' 与数据库表的'''主键'''相对应。 | |||
#: Hibernate 通过 OID 区分在内存中的持久化类; | |||
# 持久化类尽量'''不要使用 final''' 进行修饰。 | |||
#: 因为 Hibernate 中有延迟加载的机制,这个机制中会产生【代理对象】,Hibernate 产生代理对象使用的是【字节码的增强技术】完成的,其实就是产生了当前类的一个子类对象来实现的。 | |||
#: 如果使用了 final 修饰待久化类,那么就不能产生子类,从而不能产生【代理对象】,那么 Hibernate 的'''【延迟加载】策略就会失效'''。 | |||
=== 什么是 OID? === | |||
<span style="color: blue; font-size: 150%;">'''OID'''</span>(object identifier,“对象标识符”),是 hibernate 用于区分两个对象(持久化类)是否是同一个对象的标识。 | |||
持久化类的 OID 用于'''与数据库表的主键相映射''',所以一般不手动指定。 | |||
OID 在对象持久化之前是 '''null''',持久化的时候 hibernate 或者我们手动指定一个 id('''被插入到数据库当做主键,在 session中 当做索引'''),所以,需要保证 OID 与主键的一致性,比如:类型、长度等。 | |||
== 主键生成策略 == | |||
Hibernate 的主键依据:不同的主键类型、不同的数据库,可以有不同生成策略。 | |||
主键类型: | |||
# '''自然主键''':带有业务含义的主键(比如:学号,工作编号)。 | |||
#* 如果不手动指定主键就提交缓存进行更新,则会报错! | |||
#* 主键生成策略: | |||
#*# <span style="color: blue">'''assinged'''</span>:Hibernate不维护主键,开发人员需要手动设置主键; | |||
#*#* 如果不指定过元素的 <code><generator></code> 属性,则默认使用该主键生成策略。 | |||
# '''代理主键''':通过编码自动生成的,无业务含义的主键。 | |||
#* 主键生成策略: | |||
#*# <span style="color: blue">'''increment'''</span>:(由 Hibernate 提供)'''自动增长'''。 | |||
#*#* 适用主键:short、int、long 类型的主键; | |||
#*#* 不适用与并发访问数据库; | |||
#*# <span style="color: blue">'''identity'''</span>:(由数据库提供)'''自动增长'''。 | |||
#*#* 适用主键:short、int、long 类型的主键; | |||
#*#* 适用数据库:支持自动增长的数据库(如:DB2、 MySQL、 MS SQL Server、 Sybase 和 HypersomcSQL);(不适用于 Oracle) | |||
#*# <span style="color: blue">'''sequence'''</span>:(由数据库提供)'''序列'''。 | |||
#*#* 适用主键:short、int、long 类型的主键; | |||
#*#* 适用数据库:支持序列的方式的数据库(如:Oracle、db2、sap、db、postgresql); | |||
#*# <span style="color: blue">'''native'''</span>:本地策略,根据底层的数据库不同,'''自动选择'''使用 identity 还是 sequence。 | |||
#*#* 适用主键:short、int、long 类型的主键; | |||
#*# <span style="color: blue">'''uuid'''</span>:Hibernate 采用 128 位的 UUID 算法来生成标识符。 | |||
#*#: 该算法能够在网络环境中生成唯一的字符串标识符,其 UUID 被编码为一个长度为 '''32 位的十六进制字符串'''。 | |||
#*#* 适用于:字符串类型的主键。 | |||
#*#* 这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间。 | |||
== 生命周期(实体状态) == | |||
Session 的生命周期是以一个逻辑事物的开始和结束为边界,Session 的主要功能是提供创建、读取和删除映射的实体类的操作。 | |||
实体可能存在于三种状态: | |||
# '''瞬时态'''(transient):实体对象在内存是自由存在的(即为普通的 Java 对象),即:“该实体从未与任何持久化上下文关联过,它没有持久化标识”。 | |||
#* 特点: | |||
#*# 不存在待久化标识 '''OID''' (相当于主键值); | |||
#*# 尚未与 Session 关联; | |||
#*# 数据库无对应记录; | |||
#* 对象失去引用后将被 JVM 回收。 | |||
# '''持久态'''(persistent):实体对象处于 Hibernate 框架所管理的状态,即:“该实体在数据库中有对应的记录,并拥有一个持久化标识”。 | |||
#* 特点: | |||
#*# 存在待久化标识 '''OID''' ; | |||
#*# 已与 Session 关联(加入到了 Session 缓存,且 Session 未关闭); | |||
#*# 数据库有对应记录; | |||
#* 持久态对象发生改变时,Hibernate 将会依据其改变自动更新。【无需 update 等操作】 | |||
#** 在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而是发生在 Transaction 终止,执行 commit 之后。 | |||
# '''游离态'''(detached,脱管态):由持久态实体对象转变(关联的 Session 被关闭)而来。 | |||
#* 特点: | |||
#*# 存在持久化标识 '''OID'''; | |||
#*# 失去了与 Session 的关联; | |||
#*# 数据库有对应记录; | |||
#* 游离态对象发生改变时,Hibernate 不能检测到。 | |||
#*: 对象的引用依然有效,也可以继续被修改,但修改将不会影响到到数据库中的数据。 | |||
“瞬时态”与“游离态”的区别是“是否存在 OID”。(数据库对应记录不是重点)??? | |||
如: | |||
Customer customer = new Customer(); // 瞬时态 | |||
customer.setCust_id(1); // 脱管态 | |||
customer.setCust_id(null); // 瞬时态 | |||
=== 状态转换 === | |||
三种状态可以互相转换: | |||
: [[File:Hibernate 生命周期图.png|600px]] | |||
=== 持久态的自动更新 === | |||
Hibernate 会依据 persistent 状态的实体对象的属性变化,而自动更新(无需 update 等操作)数据库中相对应的记录。 | |||
注意:在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而是发生在 Transaction 终止,执行 commit 之后。 | |||
示例: | |||
: <syntaxhighlight lang="Java" highlight=""> | |||
@Test | |||
// 测试:持久态对象的自动更新 | |||
public void demo() { | |||
Session session = HibernateUtils.openSession(); | |||
Transaction tx = session.beginTransac七ion(); | |||
// 获得持久态对象. | |||
Customer customer = session.get(Customer.class, 11); | |||
// 修改持久态对象 | |||
customer.setCust name("主五"); | |||
// session.update(custorner); // 不用手动调用 update 方法就可以更新 | |||
tx.commit(); | |||
session.close(); | |||
} | |||
</syntaxhighlight> | |||
: 如上,更改持久态对象属性之后,不调用 update 等方法,依旧可以更新数据库记录。 | |||
<span style="color: blue">持久态的自动更新,依赖于 Hibernate 的一级缓存。</span> | |||
== Hibernate 缓存 == | |||
=== 一级缓存(Session 缓存) === | |||
Session 中有一个缓存,被称为“Hibernate 的<span style="color: blue; font-size: 120%">'''一级缓存'''</span>”。 | |||
Session 缓存是由一系列的 Java 集合构成的: | |||
当一个对象被加入到 Session 缓存中,这个对象的引用就加入到了 Java 的集合中,即使以后应用程序中的引用变量不再引用该对象,只要 Session 缓存不被清空,这个对象一直处于生命周期中。 | |||
作用: | |||
# 减少访问数据库的频率。 | |||
# 保证缓存中的对象与数据库中的相关记录保持同步。 | |||
==== 与实体状态 ==== | |||
Session 缓存,用于存放被当前工作单元加载的对象,这块缓存中有一个 '''map'''。 | |||
1、在执行 '''save()''' 方法后,会生成一个 '''id'''(<span style="color: blue">'''OID'''</span>),这个 id 会保存在 map 的 '''key''' 中; | |||
2、与之对应的 '''value''' 值就是该是该对象的引用,执行 '''commit()''' 方法后,数据库就有对应这条数据了,此时该实体处于“持久状态”; | |||
3、当执行完 Session.'''close()'''后,处于“游离状态”。 | |||
区分实体的三种状态: | |||
:{| class="wikitable" | |||
! 实体状态 !! OID !! Session缓存 !! 数据库 | |||
|- | |||
| 瞬时状态 || null || 不存在 || 无记录 | |||
|- | |||
| 持久状态 || 非null || 存在 || 有记录 | |||
|- | |||
| 托管状态 || 非null || 不存在 || (可能)有记录 | |||
|} | |||
==== 清理时机 ==== | |||
Session 清理缓存的时机: | |||
# 提交前:当调用 Transaction 的 commit() 方法时,commit() 方法先清理缓存(前提是:FlushMode.COMMIT/AUTO),然后再向数据库提交事务。 | |||
# 查询前:当应用程序调用 Session 的 find() 或者 iterate() 时,如果缓存中的持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能反映持久化对象的最新状态。 | |||
# flush:当应用程序显示调用 Session 的 flush() 方法的时候。 | |||
: 如下图: | |||
:{| class="wikitable" | |||
! FlashMode !! Session.find()/iterate() !! Session.commit() !! Session.flush() | |||
|- | |||
| FlashMode.AUTO || ✔ || ✔ || ✔ | |||
|- | |||
| FlashMode.COMMIT || ✘ || ✔ || ✔ | |||
|- | |||
| FlashMode.NEVER || ✘ || ✘ || ✔ | |||
|} | |||
:* 清理(✔),不清理(✘) | |||
=== 二级缓存(SessionFactory 缓存) === | |||
SessionFactory 在 Hibernate 中起到一个缓冲区作用,Hibernate 可以将自动生成的 SQL 语句、映射数据以及某些可重复利用的的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的<span style="color: blue; font-size: 120%">'''二级缓存'''</span>。 |
2022年6月10日 (五) 18:29的版本
持久化类的编写规则
如果一个 Java 类与数据库表建立了映射关系,那么这个类称为是持久化类。 (该类有对应的映射文件与数据库表相关联)
编写规则:
- 持久化类衙要提供无参数构造方法。
- 因为在 Hibernate 的底层需要使用反射生成类的实例;
- 持久化类必须:属性私有,且提供公有的 get 和 set 方法。
- 因为在 Hibernate 底 层会将查询到的数据进行封装;
- 持久化类的属性要尽量使用包装类的类型。
- 因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更消晰而基本数据类型不容易描述;
- 持久化类要有一个唯一标识 OID 与数据库表的主键相对应。
- Hibernate 通过 OID 区分在内存中的持久化类;
- 持久化类尽量不要使用 final 进行修饰。
- 因为 Hibernate 中有延迟加载的机制,这个机制中会产生【代理对象】,Hibernate 产生代理对象使用的是【字节码的增强技术】完成的,其实就是产生了当前类的一个子类对象来实现的。
- 如果使用了 final 修饰待久化类,那么就不能产生子类,从而不能产生【代理对象】,那么 Hibernate 的【延迟加载】策略就会失效。
什么是 OID?
OID(object identifier,“对象标识符”),是 hibernate 用于区分两个对象(持久化类)是否是同一个对象的标识。
持久化类的 OID 用于与数据库表的主键相映射,所以一般不手动指定。
OID 在对象持久化之前是 null,持久化的时候 hibernate 或者我们手动指定一个 id(被插入到数据库当做主键,在 session中 当做索引),所以,需要保证 OID 与主键的一致性,比如:类型、长度等。
主键生成策略
Hibernate 的主键依据:不同的主键类型、不同的数据库,可以有不同生成策略。
主键类型:
- 自然主键:带有业务含义的主键(比如:学号,工作编号)。
- 如果不手动指定主键就提交缓存进行更新,则会报错!
- 主键生成策略:
- assinged:Hibernate不维护主键,开发人员需要手动设置主键;
- 如果不指定过元素的
<generator>
属性,则默认使用该主键生成策略。
- 如果不指定过元素的
- assinged:Hibernate不维护主键,开发人员需要手动设置主键;
- 代理主键:通过编码自动生成的,无业务含义的主键。
- 主键生成策略:
- increment:(由 Hibernate 提供)自动增长。
- 适用主键:short、int、long 类型的主键;
- 不适用与并发访问数据库;
- identity:(由数据库提供)自动增长。
- 适用主键:short、int、long 类型的主键;
- 适用数据库:支持自动增长的数据库(如:DB2、 MySQL、 MS SQL Server、 Sybase 和 HypersomcSQL);(不适用于 Oracle)
- sequence:(由数据库提供)序列。
- 适用主键:short、int、long 类型的主键;
- 适用数据库:支持序列的方式的数据库(如:Oracle、db2、sap、db、postgresql);
- native:本地策略,根据底层的数据库不同,自动选择使用 identity 还是 sequence。
- 适用主键:short、int、long 类型的主键;
- uuid:Hibernate 采用 128 位的 UUID 算法来生成标识符。
- 该算法能够在网络环境中生成唯一的字符串标识符,其 UUID 被编码为一个长度为 32 位的十六进制字符串。
- 适用于:字符串类型的主键。
- 这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间。
- increment:(由 Hibernate 提供)自动增长。
- 主键生成策略:
生命周期(实体状态)
Session 的生命周期是以一个逻辑事物的开始和结束为边界,Session 的主要功能是提供创建、读取和删除映射的实体类的操作。
实体可能存在于三种状态:
- 瞬时态(transient):实体对象在内存是自由存在的(即为普通的 Java 对象),即:“该实体从未与任何持久化上下文关联过,它没有持久化标识”。
- 特点:
- 不存在待久化标识 OID (相当于主键值);
- 尚未与 Session 关联;
- 数据库无对应记录;
- 对象失去引用后将被 JVM 回收。
- 特点:
- 持久态(persistent):实体对象处于 Hibernate 框架所管理的状态,即:“该实体在数据库中有对应的记录,并拥有一个持久化标识”。
- 特点:
- 存在待久化标识 OID ;
- 已与 Session 关联(加入到了 Session 缓存,且 Session 未关闭);
- 数据库有对应记录;
- 持久态对象发生改变时,Hibernate 将会依据其改变自动更新。【无需 update 等操作】
- 在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而是发生在 Transaction 终止,执行 commit 之后。
- 特点:
- 游离态(detached,脱管态):由持久态实体对象转变(关联的 Session 被关闭)而来。
- 特点:
- 存在持久化标识 OID;
- 失去了与 Session 的关联;
- 数据库有对应记录;
- 游离态对象发生改变时,Hibernate 不能检测到。
- 对象的引用依然有效,也可以继续被修改,但修改将不会影响到到数据库中的数据。
- 特点:
“瞬时态”与“游离态”的区别是“是否存在 OID”。(数据库对应记录不是重点)??? 如: Customer customer = new Customer(); // 瞬时态 customer.setCust_id(1); // 脱管态 customer.setCust_id(null); // 瞬时态
状态转换
三种状态可以互相转换:
持久态的自动更新
Hibernate 会依据 persistent 状态的实体对象的属性变化,而自动更新(无需 update 等操作)数据库中相对应的记录。 注意:在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而是发生在 Transaction 终止,执行 commit 之后。
示例:
@Test // 测试:持久态对象的自动更新 public void demo() { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransac七ion(); // 获得持久态对象. Customer customer = session.get(Customer.class, 11); // 修改持久态对象 customer.setCust name("主五"); // session.update(custorner); // 不用手动调用 update 方法就可以更新 tx.commit(); session.close(); }
- 如上,更改持久态对象属性之后,不调用 update 等方法,依旧可以更新数据库记录。
持久态的自动更新,依赖于 Hibernate 的一级缓存。
Hibernate 缓存
一级缓存(Session 缓存)
Session 中有一个缓存,被称为“Hibernate 的一级缓存”。
Session 缓存是由一系列的 Java 集合构成的: 当一个对象被加入到 Session 缓存中,这个对象的引用就加入到了 Java 的集合中,即使以后应用程序中的引用变量不再引用该对象,只要 Session 缓存不被清空,这个对象一直处于生命周期中。
作用:
- 减少访问数据库的频率。
- 保证缓存中的对象与数据库中的相关记录保持同步。
与实体状态
Session 缓存,用于存放被当前工作单元加载的对象,这块缓存中有一个 map。
1、在执行 save() 方法后,会生成一个 id(OID),这个 id 会保存在 map 的 key 中;
2、与之对应的 value 值就是该是该对象的引用,执行 commit() 方法后,数据库就有对应这条数据了,此时该实体处于“持久状态”;
3、当执行完 Session.close()后,处于“游离状态”。
区分实体的三种状态:
实体状态 OID Session缓存 数据库 瞬时状态 null 不存在 无记录 持久状态 非null 存在 有记录 托管状态 非null 不存在 (可能)有记录
清理时机
Session 清理缓存的时机:
- 提交前:当调用 Transaction 的 commit() 方法时,commit() 方法先清理缓存(前提是:FlushMode.COMMIT/AUTO),然后再向数据库提交事务。
- 查询前:当应用程序调用 Session 的 find() 或者 iterate() 时,如果缓存中的持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能反映持久化对象的最新状态。
- flush:当应用程序显示调用 Session 的 flush() 方法的时候。
- 如下图:
FlashMode Session.find()/iterate() Session.commit() Session.flush() FlashMode.AUTO ✔ ✔ ✔ FlashMode.COMMIT ✘ ✔ ✔ FlashMode.NEVER ✘ ✘ ✔
- 清理(✔),不清理(✘)
二级缓存(SessionFactory 缓存)
SessionFactory 在 Hibernate 中起到一个缓冲区作用,Hibernate 可以将自动生成的 SQL 语句、映射数据以及某些可重复利用的的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。