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

    xiaoxiao2021-03-25  14

    Hibernate中的持久化类

    什么是持久化类?

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

    持久化类的编写规则

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

    必须提供一个无参数的public构造方法,这是因为Hibernate底层需要通过反射来生成实例;所有属性要用private修饰,对外提供public的get/set方法,这是因为Hibernate需要获取或设置属性的值;在持久化类中必须提供一个标识属性,让它与数据库中的主键相对应,我们管这个属性叫OID。 Java中是通过对象的地址来区分是否是同一个对象的,而在数据库中是通过主键来确定是否是同一个记录的,最后在Hiberimate中是通过持久化类的OID属性来区分是否是同一个对象的。持久化类中的属性尽量使用基本数据类型的包装类来定义,这是因为基本数据类型的包装类的默认值是null,而基本数据类型的默认值是0,搞不好这个0就会有很多的歧义;持久化类不能使用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语句了。 这个时候,你打开数据库中的表,就能看到插入的一条新记录了。

    转载请注明原文地址: https://ju.6miu.com/read-148834.html

    最新回复(0)