持久化类
简述
持久化:将内存中的对象持久化到数据库中的过程就是持久化。Hibernate 就是用来进行持久化的框架。
持久化类:一个 Java 对象与数据库的表建立了映射关系,那么这个类在 Hibernate 中称为是持久化类。
也可以看作:持久化类 = JavaBean + 映射文件
编写规则
1、因为 Hibernate 底层是使用反射生成实例,所以对持久化类需要提供一个无参构造方法。
2、Hibernate 底层获取和设置对象的值是通过 get
和 set
方法,所以需要对私有属性提供 public
的 get
和 set
方法。
3、Java 中通过对象的地址区分是否是同一个对象,数据库中通过主键区分是否是同一条记录,而在 Hibernate 中是通过持久化类的 OID 属性区分是否是同一个对象。所以对持久化类需要提供一个唯一标识 OID 与数据库表主键对应。
4、因为包装类类型默认值为 null
,基本数据类型有默认值,如 int
默认为 0
。假如有一个 int
类型的 score
字段用来记录分数,为 null
时表示缺考,此时 int
就不支持了。所以持久化类中属性尽量使用包装类类型。
5、延迟加载是 Hibernate 的一个优化手段,而它的原理是通过 javassist 返回一个代理对象,而 javassist 是通过底层字节码继承持久化类对持久化类实现产生代理,使用 final
描述的持久化类就不能继承,延迟加载也就会失效。所以持久化类不要用 final
修饰。
对象的三种状态
Hibernate 是持久层的框架,通过持久化类完成 ORM 操作。为了更好的管理,Hibernate 将持久化类对象分为了三种状态。
- 瞬时态:没有唯一标识 OID,且没有被 session 管理。
- 游离(托管)态:有唯一标示 OID,但没有被 session 管理。
- 持久态:有唯一标识 OID,且被 session 管理。
状态转换示例
Session session1 = HibernateUtil.openSession();
Transaction transaction1 = session1.beginTransaction();
Customer customer = new Customer(); // 瞬时态:无唯一标识,未被 session1 管理。
customer.setCust_id(1L); // 未被 session1 管理,如果数据库数据有与之对应的唯一标示(即数据库表中有一行 cust_id=1 的数据),则为游离态,否则依旧是瞬时态。
customer.setCust_name("李四");
session1.saveOrUpdate(customer); // 交由 session1 管理,且数据库数据有对应唯一标示的数据,转为持久态。
transaction1.commit();
session1.close();
Session session2 = HibernateUtil.openSession();
Transaction transaction2 = session2.beginTransaction();
System.out.println(customer); // 之前托管到的 session1 已关闭,即未被 session1 也未被 session2 管理,但有与数据库数据对应的唯一标识,此时为游离态。
session2.delete(customer); // session2 主动放弃管理,且从数据库中删除与唯一标示对应的记录,转为瞬时态。
transaction2.commit();
session2.close();
/*
描述:
瞬时态对象
获得:
Customer customer = new Customer();
状态转换:
->持久态:
session.save(customer); 、 session.saveOrUpdate(customer);
->游离态:
customer.setCust_id(1L);
游离态对象
获得:
Customer customer = new Customer();customer.setCust_id(1L);
状态转换:
->持久态
session.update(customer); 、 session.saveOrUpdate(customer);
->瞬时态:
customer.setCust_id(null);
持久态对象
获得:
session.get(Customer.class,1L); 、 session.load(Customer.class,1L);
状态转换:
->瞬时态:
session.delete(customer);
->游离态:
session.close(); 、 session.clear(); 、 session1.evict(customer);
*/
代码演示状态转换:瞬时->游离->持久->游离->瞬时
主键生成策略
主键的分类
自然主键
主键本身就是表中有意义的字段。
比如有一个人员表,每个人都会有一个身份证号(唯一不可重复),此时使用身份证号作为主键,这个主键就称为是自然主键。
代理主键
主键本身不是表中必须的字段。
如有一个人员表,每个人都会有一个身份证号(唯一不可重复),但此时使用一个与这张表逻辑不相关的 PID 字段作为主键,这种主键就称为是代理主键。
在实际开发中,尽量使用代理主键。
因为一旦自然主键参与到业务逻辑中,后期就有可能修改源代码。
的程序设计满足 OCP 原则,对程序的扩展是 open 的,对修改源码是 close 的。
生成策略
increment
Hibernate 提供的自动增长机制,使用 short
、int
、long
类型的主键,在单线程程序中使用。
发送一条 sql:select max(id) from 表
查询最大 id
,然后用 id+1
作为下一条记录的主键。
identity
适用 short
、int
、long
类型的主键,使用的是数据库底层的自增机制,适用于有自增机制的数据库(MySQL、MSSQL)。
sequence
适用 short
、int
、long
类型的主键,采用的是序列的方式,适用于支持序列机制的数据库(Oracle)。
uuid
适用于字符串类型主键,由 Hibernate 随机生成字符串主键。
native
本地策略,可以在 identity
和 sequence
间自动切换。
assigned
Hibernate 放弃主键的管理,通过手动编码给主键赋值。
foreign
依赖外部主键,适用于一对一关联映射情况下使用。
评论区