Hibernate入门第五讲——Hibernate持久化类与主键生成策略

Hibernate中的持久化类

什么是持久化类?

在给出持久化类的定义之前,我先说说啥是持久化。持久化是指将内存中的一个对象持久化到数据库当中的过程。现在,可以说说什么是持久化类了,一个Java对象与数据库里的表建立了映射关系,那么这个类在Hibernate中就被称为是持久化类。在Hibernate中持久化类的英文名称是Persistent Object(简称PO),PO=POJO+hbm映射配置文件,也就是说持久化类=Java类+映射配置文件。

持久化类的编写规则

对于Hibernate中的持久化类,有如下编写规则:

  1. 必须提供一个无参数的public构造方法,这是因为Hibernate底层需要通过反射来生成实例;
  2. 所有属性要用private修饰,对外提供public的get/set方法,这是因为Hibernate需要获取或设置属性的值;
  3. 在持久化类中必须提供一个标识属性,让它与数据库中的主键相对应,我们管这个属性叫OID。
    Java中是通过对象的地址来区分是否是同一个对象的,而在数据库中是通过主键来确定是否是同一个记录的,最后在Hiberimate中是通过持久化类的OID属性来区分是否是同一个对象的。
  4. 持久化类中的属性尽量使用基本数据类型的包装类来定义,这是因为基本数据类型的包装类的默认值是null,而基本数据类型的默认值是0,搞不好这个0就会有很多的歧义;
  5. 持久化类不能使用final修饰符修饰,这是因为与延迟加载有关系,延迟加载本身是Hibernate一个优化的手段,它返回的是一个利用javassist技术产生的代理对象。javassist技术可以对没有实现接口的类产生代理,该技术其实使用了非常底层的字节码增强技术,继承这个类进行代理,即可产生一个代理对象,如果一旦这个类不能被继承,那么它就不能产生代理对象,这样一来,延迟加载就失效了,Hibernate就不能进行优化了,load方法就和get方法一点区别也没有了。

对于第1、2点,勿须多言,理解起来应该非常容易,后面3点,其实我已经说得蛮清楚了,下面我再费笔墨解释一通。

为何持久化类必须提供一个标识属性OID,让它与数据库中的主键对应呢?

OID指的是与数据库中表的主键对应的属性。Hibernate框架是通过OID来区分不同的持久化对象的,如果在内存中有两个相同的OID对象,那么Hibernate认为它们是同一个对象。大家理解起来不是很好理解,它涉及到关于Hibernate缓存的概念,因为Hibernate是对数据库直接操作,那么我们为了优化它呢,肯定提供了一些缓存的策略。那么在缓存里面我们怎么知道这个对象重不重复呢?我们是通过OID来区分的。

为何持久化类中的属性应尽量使用基本数据类型的包装类?

使用基本数据类型是没有办法去描述不存在的概念的,如果使用包装类型,它就是一个对象,对于对象它的默认值是null,我们知道如果它为null,就代表不存在,那么它就可以帮助我们去描述不存在的概念了。

为何持久化类不能使用final修饰符修饰?

假设,持久化类使用final修饰符来修饰,就像下面这样:
在这里插入图片描述
此时,如果我们使用load方法根据id来查询,那么采用的是立即加载,当执行到这一行代码的时候,就会马上发送sql语句去查询,也即是说load方法就和get方法一点区别也没有了,而且load方法查询后返回的是真实对象本身。
在这里插入图片描述

Hibernate的主键生成策略

主键的分类

定义hbm.xml映射文件和POJO类时都需要定义主键,Hibernate中定义的主键类型包括自然主键和代理主键:

  • 自然主键(也称之为业务主键):主键的本身就是表中的一个字段(实体中的一个具体属性),也即具有业务含义的字段作为主键。比如说创建一个人员表,人员都会有一个身份证号(唯一的不可重复的),如果使用了身份证号作为主键,那么这种主键就称为是自然主键;
  • 代理主键(也称之为逻辑主键):主键的本身不是我们表中必须的一个字段(不是实体中的某个具体属性),也即不具有业务含义的字段作为主键。比如说还是创建一个人员表,没有使用人员中的身份证号,用了一个与这个表根本不相关的一个字段,例如ID、PNO,那么这种主键就称为是代理主键。

建议:在企业开发中,尽量使用代理主键!因为一旦你的自然主键参与到了你的业务逻辑当中,那么后期就有可能要修改源代码。一个好的程序的设计,要满足一个OCP原则,即对程序的扩展是open的,对修改源码是close的

主键生成策略

在实际开发中,一般不允许用户手动设置主键,一般会将主键交给数据库或者手动编写程序进行设置。在Hibernate中为了减少程序编写,提供了很多种主键的生成策略。
在这里插入图片描述

演示native主键生成策略

首先,我们要搭好Hibernate的开发环境,读过我前面文章的童鞋,应该可以快速搭建好的,在此不做过多赘述。
然后,看一下你Hibernate核心配置文件中的hibernate.hbm2ddl.auto属性值是否为create,如果不是,那么就设置为create,因为create一般就在测试时使用,它每次都会创建一张新的表。
在这里插入图片描述
接着,将映射配置文件(例如Customer.hbm.xml)中的主键生成策略设置为native,之前我们一直使用的就是这种主键生成策略,只不过那时不明所以而已。
在这里插入图片描述
最后,我们使用save()方法保存一条记录,如下:
在这里插入图片描述
运行上面的单元测试方法,不出意外,我们就能在Eclipse的控制台上看到建表和向表中插入的sql语句了。
在这里插入图片描述

演示increment主键生成策略

现在编程来演示increment这个主键生成策略,还是蛮麻烦的!因为你得弄两个线程一起往数据库表里面去插入记录。所以,大家可以按照我下面的步骤来演示increment这个主键生成策略。
第一步,看一下你Hibernate核心配置文件中的hibernate.hbm2ddl.auto属性值是否为create,如果不是,那么就设置为create,因为create一般就在测试时使用,它每次都会创建一张新的表。
在这里插入图片描述
第二步,将映射配置文件(例如Customer.hbm.xml)中的主键生成策略设置为increment。
在这里插入图片描述
第三步,开启两个线程一起往数据库表里面去插入记录,这儿还一定得debug断点调试。
在这里插入图片描述
首先,以debug的方式运行demo01()方法,在数据库里面先创建一张表。
在这里插入图片描述
然后,在以debug的方式运行demo01()方法和demo02()方法之前,将Hibernate核心配置文件中的hibernate.hbm2ddl.auto属性值设置为update,这样如果数据库中已经有了表,那么就不重新创建了,而是使用原有表。
在这里插入图片描述
接着,以debug的方式运行demo01()方法,如下图所示。
在这里插入图片描述
紧接着,以debug的方式运行demo02()方法,如下图所示。
在这里插入图片描述
再次回到demo01()方法中,提交事务。
在这里插入图片描述
这个时候再回到demo02()方法中,提交事务,这时就会报主键冲突的错。
在这里插入图片描述
所以,你要是采用increment这种主键生成策略,应该在单线程程序中使用,一定不要在有多线程的情况下使用。

演示identity主键生成策略

首先,看一下你Hibernate核心配置文件中的hibernate.hbm2ddl.auto属性值是否为create,如果不是,那么就设置为create,因为create一般就在测试时使用,它每次都会创建一张新的表。
在这里插入图片描述
然后,将映射配置文件(例如Customer.hbm.xml)中的主键生成策略设置为identity。
在这里插入图片描述
最后,我们使用save()方法保存一条记录,如下:
在这里插入图片描述
运行上面的单元测试方法,不出意外,我们就能在Eclipse的控制台上看到建表和向表中插入的sql语句了。
在这里插入图片描述

演示uuid主键生成策略

首先,看一下你Hibernate核心配置文件中的hibernate.hbm2ddl.auto属性值是否为create,如果不是,那么就设置为create,因为create一般就在测试时使用,它每次都会创建一张新的表。
在这里插入图片描述
然后,将实体类(例如Customer.java)中的cust_id属性的类型由Long改为String,因为uuid这种主键生成策略适用于字符串类型的主键。
在这里插入图片描述
接着,将映射配置文件(例如Customer.hbm.xml)中的主键生成策略设置为uuid。
在这里插入图片描述
最后,我们使用save()方法保存一条记录,如下:
在这里插入图片描述
运行上面的单元测试方法,不出意外,我们就能在Eclipse的控制台上看到建表和向表中插入的sql语句了。
在这里插入图片描述
这个时候,你打开数据库中的表,就能看到插入的一条新记录了,并且主键是使用Hibernate中的随机方式生成一个的字符串。
在这里插入图片描述

演示assigned主键生成策略

首先,看一下你Hibernate核心配置文件中的hibernate.hbm2ddl.auto属性值是否为create,如果不是,那么就设置为create,因为create一般就在测试时使用,它每次都会创建一张新的表。
在这里插入图片描述
然后,将实体类(例如Customer.java)中的cust_id属性的类型由String改为Long,即恢复到原来的样子。
在这里插入图片描述
接着,将映射配置文件(例如Customer.hbm.xml)中的主键生成策略设置为assigned。
在这里插入图片描述
最后,我们使用save()方法保存一条记录,如下:
在这里插入图片描述
运行上面的单元测试方法,不出意外,我们就能在Eclipse的控制台上看到建表和向表中插入的sql语句了。
在这里插入图片描述
这个时候,你打开数据库中的表,就能看到插入的一条新记录了。
在这里插入图片描述

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李阿昀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值