J2EE系列之Hibernate4学习笔记(三)--映射对象标识符(OID)

xiaoxiao2021-02-27  432

一、hibernate使用对象标识符(OID)来区分对象

看如下一个例子:

1.新建工程Hibernate03;

2.新建类Student以及它的映射文件Student.hbm.xml

package com.test.model; public class Student { private long id; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } }

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.test.model"> <class name="Student" table="t_student"> <id name="id" column="stuId"> <generator class="native"></generator> </id> <property name="name"></property> </class> </hibernate-mapping> 3.hibernate配置文件以及HibernateUtil.java文件拷贝到工程中;

4.新建测试类:

package com.test.service; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.test.model.Student; import com.test.util.HibernateUtil; public class StudentTest { public static void main(String[] args) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 获取Session工厂 Session session=sessionFactory.openSession(); // 生成一个session session.beginTransaction(); // 开启事务 Student s1 = (Student)session.get(Student.class, Long.valueOf(2)); Student s2 = (Student)session.get(Student.class, Long.valueOf(3)); Student s3 = (Student)session.get(Student.class, Long.valueOf(2)); System.out.println(s1==s2); System.out.println(s1==s3);//s1和s3指向的是同一个对象 session.getTransaction().commit(); // 提交事务 session.close(); // 关闭session } } 此时的数据库中数据为:

运行测试函数,控制台输出结果为:

先看结果:上面的结果显示s1与s2是不同的对象,而s1与s3是指向同一个对象的,这个就是hibernate使用对象标识符来表示对象的结果。看第一部分,这里只有两个sql语句,分别是取对象s1和s2的sql语句,而s3并没有新的sql语句,这说明了取对象s3的时候并没有到数据库中去操作。整个过程如下图:

当取对象s1的时候,hibernate会在数据库表t_student中取出这个对象放在缓存中,这个对象的OID值与其在表中的主键值是相同的,故其OID=1,s1指向缓存中OID等于1的这个对象。当取s2的时候,s2对象的主键值是2,hibernate会先到session缓存中看有没有OID值等于2的对象,没有,hibernate会在数据库中取出主键为2的对象放在缓存中,使s2指向这个对象,并给这个对象的OID赋值为2;当取s3的时候,s3的主键值为1,hibernate到缓存中查找有没有OID值等于1的对象,此时有,就直接将s3指向这个对象。

所以,这里s1和s3是指向缓存中同一个对象的。

二、Hibernate对象标识符生成策略

上面说到了对象标识符其实就是对象的主键值。所谓对象标识符的生成策略也就是对象主键的生成策略。

首先说一下主键分为代理主键和业务主键两种,代理主键是不具有业务性的主键,比如说上面数据库表中的主键是1、2、3等。业务主键是具有业务性的,比如说学生的学号,这个是唯一的,但是学号是具有业务意义的。

当数据库建立完成后,如果数据库中的数据不会经常变动的话,可以使用业务主键,这样会带来一些方便,不需要在额外搞一个字段。如果业务需要经常变动的,使用代理主键会比较好一些。

看一下上一个工程中主键的生成方式:

这里的主键生成方式为native方式。hibernate常用的主键生成方式有如下几种:

1,increment 由Hibernate 自动以递增的方式生成标识符,适用代理主键; 2,identity 由底层数据库生成标识符;适用代理主键; 3,sequcence 由Hibernate 根据底层数据库的序列来生成标识符;适用代理主键; 4,hilo Hibernate 根据high/low 算法来生成标识符。适用代理主键 5,native 根据底层数据库对自动生成标识符的支持能力, 来选择identity,sequence 或hilo;适用代理主键;

其中,increment为hibernate自动以递增的方式生成主键,看如下例子:

1.修改映射文件为increment方式:

<hibernate-mapping package="com.test.model"> <class name="Student" table="t_student"> <id name="id" column="stuId"> <generator class="increment"></generator> </id> <property name="name"></property> </class> </hibernate-mapping> 2.删除数据库中t_student表,使其重新生成;

3.写一个测试类:

package com.test.service; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.test.model.Student; import com.test.util.HibernateUtil; public class StudentTest2 { public static void main(String[] args) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 获取Session工厂 Session session=sessionFactory.openSession(); // 生成一个session session.beginTransaction(); // 开启事务 Student s = new Student(); s.setName("张三"); session.save(s); session.getTransaction().commit(); // 提交事务 session.close(); // 关闭session } } 执行这个测试函数,控制台运行结果为:

可以看到这里hibernate执行了2条sql语句。第一条语句是hibernate到数据库中查找当前的最大主键值是多少,第二条语句执行的时候把最大主键值加1插入到数据库中。

这里主键值的大小是hibernate来自动完成的。看一下此时生成的t_student表结构为:

这里主键并没有设置自增这一项。可见increment方式的主键自增是hibernate实现的,而不是数据库实现的。

identity方式是由数据库来实现主键自增的。

1.修改映射文件为:

<hibernate-mapping package="com.test.model"> <class name="Student" table="t_student"> <id name="id" column="stuId"> <generator class="identity"></generator> </id> <property name="name"></property> </class> </hibernate-mapping> 2.删除表格t_student并重新运行测试函数。控制台输出为:

这里hibernate只执行了一条插入语句,只插入了name一个字段。这里主键字段是由数据库自动赋值的。此时生成的t_student表结构为:

可以看到此时数据库对主键设置了自增选项。

sequence由Hibernate 根据底层数据库的序列来生成标识符,mysql不支持这个方式,oracle支持这种方式。

hilo是Hibernate 根据high/low 算法来生成标识符。

native根据底层数据库对自动生成标识符的支持能力, 来选择identity,sequence 或hilo。所以对于mysql而言,native方式与identity方式是相同的。

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

最新回复(0)