Hibernate(2)之持久化类与主键生成策略

Hibernate(2)之持久化类与主键生成策略

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

持久化类

简述

持久化:将内存中的对象持久化到数据库中的过程就是持久化。Hibernate 就是用来进行持久化的框架。
持久化类:一个 Java 对象与数据库的表建立了映射关系,那么这个类在 Hibernate 中称为是持久化类。

也可以看作:持久化类 = JavaBean + 映射文件

编写规则

1、因为 Hibernate 底层是使用反射生成实例,所以对持久化类需要提供一个无参构造方法。
2、Hibernate 底层获取和设置对象的值是通过 getset 方法,所以需要对私有属性提供 publicgetset 方法。
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 提供的自动增长机制,使用 shortintlong 类型的主键,在单线程程序中使用。
发送一条 sql:select max(id) from 表 查询最大 id,然后用 id+1 作为下一条记录的主键。

identity

适用 shortintlong 类型的主键,使用的是数据库底层的自增机制,适用于有自增机制的数据库(MySQL、MSSQL)。

sequence

适用 shortintlong 类型的主键,采用的是序列的方式,适用于支持序列机制的数据库(Oracle)。

uuid

适用于字符串类型主键,由 Hibernate 随机生成字符串主键。

native

本地策略,可以在 identitysequence 间自动切换。

assigned

Hibernate 放弃主键的管理,通过手动编码给主键赋值。

foreign

依赖外部主键,适用于一对一关联映射情况下使用。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/hibernate2.html

Buy me a cup of coffee ☕.