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

一、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方式是相同的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值