版权声明:本文为 小异常 原创文章,非商用自由转载-保持署名-注明出处,谢谢!
本文网址:https://blog.csdn.net/sun8112133/article/details/106151361
本篇博客主要讲解两个重要的知识:持久化类 和 主键生成策略。
一、持久化类
1、持久化类概述
持久化类 就是将内存中某个对象的属性保存到数据库的过程。Hibernate 框架就是用来进行持久化的框架。如果一个 Java 类与数据表建立了映射关系,那么这个类在 Hibernate 中称为是 持久化类。
持久化类 = Java类 + 映射文件
2、编写规则
编写一个 持久化类 需要遵循以下五个规则:
1)无参构造器
对 持久化类 提供一个无参数的构造方法,因为 Hibernate 底层需要使用反射机制来创建实例。
2)私有属性
属性需要私有化。对私有属性要提供
public
修饰的get()
和set()
方法,因为 Hibernate 要通过get()
和set()
方法来获取和设置对象的值。
3)OID 属性
为 持久化类 提供一个 OID 属性(对象唯一标识的属性)与数据库的主键对应。
比如我们之前在 Java 中通过对象的地址值来区分是否是同一个对象,在数据库中通过主键来确定是否是同一个记录,然而在 Hibernate 中是通过持久化类的 OID 的属性来区分是否是同一个对象。
4)类型使用包装类
持久化类 中属性尽量使用包装类型,因为有的基本数据类型的默认值是 0,那么 0 就会有很多的歧义。而包装类型默认值是
null
,它代表空,没有任何歧义。
5)持久化类不要使用 final 修饰
持久化类 不要使用
final
修饰,因为 Hibernate 后期可能会使用延迟加载对该类采取一系列的优化手段(延迟加载这个概念后续博客会有专门讲解,简单的说延迟加载是通过代理模式实现的)。它最终会返回一个代理对象,如果这个类不能被继承,那么就不能产生代理对象,延迟加载就会失效。
3、三种状态
Hibernate 是持久层框架,通过 持久化类 完成 ORM (对象关系映射)操作。Hibernate 为了更好的管理 持久化类,将 持久化类 分成了三种状态:
1)瞬时态(transient)
这种对象没有唯一的标识 OID,没有被 session 管理,称为是 瞬时态对象。
2)持久态(persistent)
这种对象有唯一标识 OID,被 session 管理,称为是 持久态对象。持久化类 的 持久态对象,可以自动更新数据库哦。
3)脱管态(detached)
这种对象有唯一标识 OID,没有被 session 管理,称为 脱管态对象。
4)测试三种状态
@Test
public void demo1() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer c = new Customer(); // 瞬时态对象:没有唯一标识OID,没有被session管理
c.setCust_name("赵六");
session.save(c); // 持久化对象:有唯一标识OID,被session管理
// 这个时候可以对持久化对象进行操作
tx.commit();
session.close();
System.out.println(c.getCust_name()); // 脱管态对象:有唯一标识OID,没有被session管理,因为session已经被关闭了
}
4、状态转换
1)瞬时态对象
-
获得
Customer customer = new Customer();
-
状态转换
- 瞬时 --> 持久
- save(Object obj);
- saveOrUpdate(Object obj);
- 瞬时 --> 脱管
- customer.setCust_id(1);
- 瞬时 --> 持久
2)持久态对象
- 获得
- 可以通过 get() 、load() 、find() 、iterate() 方法
- 如:
Customer customer = session.get(Customer.class, 1L);
- 状态转换
- 持久 --> 瞬时
- delete();
- 持久 --> 脱管
- close();
- clear();
- evict(Object obj);
- 持久 --> 瞬时
3)脱管态对象
- 获得
Customer customer = new Customer();
customer.setCust_id(1L);
- 状态转换
- 脱管 --> 持久
- update();
- saveOrUpdate();
- 脱管 --> 瞬时
customer.setCust_id(null);
- 脱管 --> 持久
5、持久类特性
持久态对象 可以自动更新数据库,它底层的原理依赖了 Hibernate 的一级缓存(关于缓存相关知识后续博客会专门进行讲解)。
@Test
// 持久化对象自动更新数据库
public void demo2() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = session.get(Customer.class, 1);
customer.setCust_name("张三"); // 如果更新内容和数据库内容一致,则只查询,不更新。
tx.commit();
session.close();
}
二、主键生成策略
1、主键分类
1)自然主键
自然主键 是指主键的本身就是表中的一个字段,比如一个人员表,人员都会有一个身份证号(身份证号是唯一且不可重复的),那么可以使用身份证号作为主键,那这种主键就称为是 自然主键。
2)代理主键
代理主键 是指主键的本身不是表中必须的一个字段,比如一个人员表,没有使用人员中的身份证号,而是用了一个与这个表不相关的字段ID。那么这种主键就称为是 代理主键。
我们在实际开发中,尽量要使用 代理主键。因为一旦自然主键参与到业务逻辑中,那后期有可能需要修改源代码。一个好的程序设计要满足 OCP 原则,也就是对程序的扩展是 open,对修改源代码是 close。
2、Hibernate 的主键生成策略
在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库管理,手动编写程序进行设置。在 Hibernate 中为了减少程序的编写,提供了很多种的 主键生成策略。
1)increment
该策略采用了自然增长机制,它适用 short、int、long 类型的主键。一般要在单线程程序中使用。它首先先发送一条语句:
select max(id) from 表名;
,然后让id+1
作为下一条记录的主键。
2)identity
该策略采用了数据库底层的自动增长机制(MySQL、MSSQL 适用),它适用 short、int、long 类型的主键,但是像 Oracle 这种数据库不能使用此策略,因为它没有自动增长机制。
3)sequence
该策略采用的是序列方式(Oracle支持序列),它适用 short、int、long 类型的主键,但是像 MySQL 这种数据库就不能使用此策略,因为它不支持序列。
4)uuid
该策略采用的是 Hibernate 中随机生成字符串主键的方式,它适用于字符串类型主键。
5)native
该策略是本地策略,它可以在 identity 策略 和 sequence 策略 之间进行自动切换,这个策略很常用。
6)ssigned
该策略是让 Hibernate 主动放弃主键管理,但是需要通过手动编写程序或者用户自己设置。
7)foreign
该策略是外部的。在一对一的一种关联映射的情况下才会使用,这个策略不常用,大家了解即可。