Hibernate系列之ID生成策略

一、概述

  hibernate中使用两种方式实现主键生成策略,分别是XML生成id和注解方式(@GeneratedValue),下面逐一进行总结。

二、XML配置方法

  这种方式是在XX.hbm.xml文件中对generator进行配置,eg:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.test.demo">

    <class name="Student">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <property name="age"></property>
    </class>
</hibernate-mapping>

  常用的生成策略有以下几种:

  identity:对DB2,Mysql,MS SQL Server等的内置标识字段提供支持,返回的标识符是long,short或者int类型

  native:可以是identity类型、sequence类型或者hilo类型,取决于不同的底层数据库

  sequence:在Oracle,SAP DB中使用序列(sequence)

  uuid:使用一种128位的UUID算法产生的字符类型标识,像IP地址一样全网唯一

三、注解方式生成ID:@GeneratorValue

  标准的annotation方式的主键生成策略如下:

  • AUTO:可以是identity类型或者是sequence类型或者是table类型,取决于底层的数据库

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Person
{
    private String name;
    private int age;
    private int id;
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public int getAge()
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
}

  • TABLE:使用表保存id值,即会为应用的表创建一张专门保存id的表

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;

@Entity
public class Person
{
    private String name;
    private int age;
    private int id;
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public int getAge()
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
    @Id
    @TableGenerator(name="personID",table="personID_DB",pkColumnName="key_value",pkColumnValue="pk_value",valueColumnName="person",allocationSize=1)
    @GeneratedValue(strategy=GenerationType.TABLE,generator="personID")
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
}

  • IDENTITY:identity column

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;

@Entity
public class Person
{
    private String name;
    private int age;
    private int id;
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public int getAge()
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
    @Id

    @GeneratedValue(strategy=GenerationType.IDENTITY)
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
}

  • SEQUENCE:sequence

四、联合主键生成策略

  有的时候我们需要将一个实体的2个或多个字段联合起来作为主键,就是说,不能有2个或多个对象的这几个字段值都相同的情况发生。现在我们要将Person字段的id和name字段联合作为主键:

@Entity
public class Person
{
    //现在id和name组成联合主键
    private int id;
    private String name;
    private int age;
    ...
}
  1. 首先将联合主键的属性提取出来,重新编写一个pojo类(原pojo类中的id,name要删除 并新加入属性“PersonPK”)
  2. 新建pojo类必须实现 java.io.Serializable 序列化接口
  3. 新pojo类要重写equals和hashCode方法
public class PersonPK implements Serializable
{
    private String name;
    private int id;
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
    @Override
    public int hashCode()
    {
        return this.name.hashCode();
    }
    @Override
    public boolean equals(Object obj)
    {
        if(obj instanceof PersonPK) {
            PersonPK pk = (PersonPK)obj;
            if(this.id == pk.getId() && this.name.equals(pk.getName())) {
              return true;
            }
        }
        return false;

    }
}

   联合主键生成策略XML配置方法:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.test.demo">

    <class name="Person">
        <composite-id name="personPK" class="com.test.demo.PersonPK">
                <key-property name="id"></key-property>
                <key-property name="name"></key-property>
            </composite-id>
            <property name="age" />
    </class>
</hibernate-mapping>

  联合主键ID生成策略的Annotation版本,共有三种方式,前三步骤一样,另外:

  方法1、在新类PersonPK前写@Embeddable,在原Person类的新属性PersonPK的get方法前写@id

@Embeddable
public class PersonPK implements Serializable
{
    private static final long serialVersionUID = -7068850328521576106L;
    private String name;
    private int id;
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
    @Override
    public int hashCode()
    {
        return this.name.hashCode();
    }
    @Override
    public boolean equals(Object obj)
    {
        if(obj instanceof PersonPK) {
            PersonPK pk = (PersonPK)obj;
            if(this.id == pk.getId() && this.name.equals(pk.getName())) {
              return true;
            }
        }
        return false;

    }
}

  Person类中:

@Entity
public class Person
{
    private PersonPK personPK;
    private int age;

    public int getAge()
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
    @Id
    public PersonPK getPersonPK()
    {
        return personPK;
    }
    public void setPersonPK(PersonPK personPK)
    {
        this.personPK = personPK;
    }
}

  方法2、新类无需添加注解,只需在原类Person新属性PersonPK的get方法前写@EmbeddID即可

@Entity
public class Person
{
    private PersonPK personPK;
    private int age;

    public int getAge()
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
    @EmbeddedId
    public PersonPK getPersonPK()
    {
        return personPK;
    }
    public void setPersonPK(PersonPK personPK)
    {
        this.personPK = personPK;
    }
}

  方法3、新pojo类无需加注解,原pojo类的id,name属性保留不变,也无需新增“TercherPK”属性。 只在id,name的get方法前都加@Id,并在原pojo类前加@IdClass(PersonPK.class):

  原类Person:

@Entity
@IdClass(PersonPK.class)
public class Person
{
    private int age;
    private String name;
    private int id;
    @Id
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    @Id
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
    public int getAge()
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
}

  运行测试程序(针对上述三种方法,测试用例需要稍作修改,这里不在赘述):

public class PersonTest
{
    private static SessionFactory sf=null;
    @BeforeClass
    public static void beforeClass()
    {
        sf=new AnnotationConfiguration().configure().buildSessionFactory();
    }
    @Test
    public void test()
    {
        PersonPK personPK=new PersonPK();
        personPK.setId(1);
        personPK.setName("xujian");
        Person p=new Person();
        p.setAge(23);
        p.setPersonPK(personPK);
        Session session=sf.openSession();
        session.beginTransaction();
        session.save(p);
        //提交事物
        session.getTransaction().commit();
        session.close();
        sf.close();
    }
    @AfterClass
    public static void afterClass()
    {
        sf.close();
    }
}

  可以看到:

  生成的Person表中id和name组成联合主键

  

  

  

  

  

  

时间: 2024-10-10 02:07:05

Hibernate系列之ID生成策略的相关文章

hibernate(四)ID生成策略

一.ID生成策略配置 1.ID生成方式在xml中配置方式: <?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 p

Rhythmk 学习 Hibernate 03 - Hibernate 之 延时加载 以及 ID 生成策略

Hibernate 加载数据 有get,跟Load 1.懒加载: 使用session.load(type,id)获取对象,并不读取数据库,只有在使用返回对象值才正真去查询数据库. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test    public void  test1()    {        Session session = null;         try {             session = Hiber

hibernate 中mysql的id生成策略

数据库的规划和操作号码大全中,咱们一般会给表建立长尾关键词挖掘工具的主键. 主键,可以分为天然主键和署理主键. 天然主键表明:选用具有事务逻辑意义的字段作为表的主键.比方在用户信息表中,选用用户的身份证号码作为主键.可是这样一来,跟着事务逻辑的变化,主键就有可能要更改.比方,假定哪天身份证号码升级成19,2位,那....... 署理主键:在表中人为的添加一个字段,该字段并没有表明任何的事务逻辑,仅仅用来标识一行数据.比方说在用户信息表中,添加一个用户ID的字段.用来表明该条用户信息的记录. 一般

Hibernate中ID生成策略

四.ID生成策略 第一种:XML配置ID 通过为<id>元素增加<generator>子元素,该子元素拥有class属性.常用的class属性有: (1)increment:用于为long.short.或者int类型生成唯一标识.只有在没有其他进程往同一张表中插入数据的时候才能使用.在集群不要使用.(极少使用) (2)native:让数据库自动选择identity,sequence,或者其他. (3)uuid:128位的UUID算法,产生String类型ID (4)identity

hibernate ID生成策略配置

1.Student.hbm.xml配置 <hibernate-mapping package="com.wxh.hibernate.model"> <class name="Student" > <id name="id"> <generator class="uuid"></generator> </id> <property name="

[Hibernate开发之路](4)ID生成策略

一 对象关系数据库映射之Id 被映射的类必须定义相应数据库表主键字段.大多数类有一个JavaBeans风格的属性, 为每个实例包括唯一的标识. <id> 元素定义了该属性到数据库表主键字段的映射. <id name="propertyName" type="typename" column="column_name" unsaved-value="null|any|none|undefined|id_value&quo

Hibernate学习笔记(4)ID生成策略

一 对象关系数据库映射之Id 被映射的类必须定义对应数据库表主键字段.大多数类有一个JavaBeans风格的属性, 为每一个实例包含唯一的标识.<id> 元素定义了该属性到数据库表主键字段的映射. <id name="propertyName" type="typename" column="column_name" unsaved-value="null|any|none|undefined|id_value&quo

Hibernate的主键生成策略的介绍

Hibernate主键的生成策略: 就是在配置文件中class中的配置项 <id name="id" column="id"> <generator class="increment"/> </id> native:适用于代理主键,代理主键就是没有业务含义的主键,通常用id表示,根据底层数据库对自动生成标识符的能力来选择identity.sequence.hilo identify:适用于代理主键,有底层数据库

”伪集群“导致的Hibernate主键increment生成策略异常

一.问题描述: 一个小型WEB应用,单点部署(一份Tomcat+一份MySQL),无集群需求. 有一张数据表的主键使用Hibernate的increment生成策略: <id name="id" column="id"> <generator class="increment" /> </id> 但当有多人在同时调试该表的写入模块时,会抛出如下异常: com.mysql.jdbc.exceptions.jdbc