转载

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类型,取决于底层的数据库
Hibernate系列之ID生成策略
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的表
Hibernate系列之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
Hibernate系列之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  @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组成联合主键

Hibernate系列之ID生成策略

正文到此结束
Loading...