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;
    }
}
View Code
  • 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;
    }
}
View Code
  • 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;
    }
}
View Code
  • 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組成聯合主鍵

  

  

  

  

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM