`

hibernate的id生成策略

 
阅读更多
查看文章
   
2011-09-27 17:40
Hibernate的id生成策略有下面几种:
1.Increment

用于为long,short或者int类型生成唯一标识,只有在没有其他进程往同一张表中插入数据库时才能使用。在集群下不要使用。

对于集群为什么不要使用,是因为在一个大型的项目中如果我们有很多的服务器为项目提供服务,这样就会出项一种情况,A服务在15:25拿到数据库中的数据的 id为15,此时B服务器向数据库中插入了一条数据,这时数据库中的id为16了,但A服务中的session依旧保存着15,但下一条数据通过A服务向数据库中保存数据的时候session会为id赋值为16,可数据库中的id已经为16了,所以这时保存就会出错。


2.identity:

对 DB2,MySQL,MS SQL Server,Sybase 和 HypersonicSQL 的内置标识字段提供支持。返回的标识符是 long,short 或者 int 类型的。


3.sequence

在 DB2,PostgreSQL,Oracle,SAP DB,McKoi 中使用序列(sequence), 而在 Interbase

中使用生成器(generator)。返回的标识符是 long,short 或者 int 类型的。


4.hilo

使用一个高/低位算法高效的生成 long,short 或者 int 类型的标识符。给定一个表和字段(默认分别是 hibernate_unique_key 和 next_hi)作为高位值的来源。高/低位算法生成的标识符只在一个特定的数据库中是唯一的。


5.seqhilo

使用一个高/低位算法来高效的生成 long,short 或者 int 类型的标识符,给定一个数据库序列(sequence)的名字。


6.uuid

基于一个自定义的算法生成一个128位的UUID。所产生的价值
表示为32个十六进制数字的字符串。


7.guid

在 MS SQL Server 和 MySQL 中使用数据库生成的 GUID 字符串。


8.native

根据底层数据库的能力选择 identity、sequence 或者 hilo 中的一个。


9.assigned

让应用程序在调用 save() 之前为对象分配一个标识符。这是 <generator> 元素没有指定时的默认生成策略。


10.select

通过数据库触发器选择一些唯一主键的行并返回主键值来分配一个主键。


11.foreign

使用另外一个相关联的对象的标识符。它通常和 <one-to-one> 联合起来使用。


12.sequence-identity

一种特别的序列生成策略,它使用数据库序列来生成实际值,但将它和 JDBC3 的getGeneratedKeys 结合在一起,使得在插入语句执行的时候就返回生成的值。目前为止只有面向 JDK 1.4 的 Oracle 10g 驱动支持这一策略。由于 Oracle 驱动程序的一个 bug,这些插入语句的注释被关闭了。

我们通常用的比较多的就是native、identity、sequence在一些情况下我们会用到uuid,其他的就用的很少了。


举例说明uuid

下面来测试一下uuid,还用原来的Student类,既然是测试uuid那我们的id就必须为String类型了。


Student类

package cc.tukai.entity;

import java.io.Serializable;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.Table;

//@Entity

//@Table(name = "Student")

public class Student implements Serializable {

         private static final long serialVersionUID = -5596241291862147220L;

         private String id;

         private String name;

         private int age;

         //@Id

         public String getId() {

                   return id;

         }

         public void setId(String id) {

                   this.id = 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;

         }


Student.hbm.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 package="cc.tukai.entity">

         <class name="Student" table="student">

                   <id name="id" column="id">

                            <generator class="uuid"></generator>

                   </id>

                   <property name="name" type="java.lang.String">

                            <column name="name" length="32"></column>

                   </property>

                   <property name="age" type="java.lang.Integer">

                            <column name="age" length="10"></column>

                   </property>

         </class>

</hibernate-mapping>


hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

         <session-factory>

                   <!-- Database connection settings -->

                   <property name="connection.driver_class">com.mysql.jdbc.Driver</property>

                   <property name="connection.url">jdbc:mysql://127.0.0.1/hibernate</property>

                   <property name="connection.username">root</property>

                   <property name="connection.password">1234</property>

                   <!-- SQL dialect -->

                   <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

                   <!-- Echo all executed SQL to stdout -->

                   <property name="show_sql">true</property>

                   <!-- Drop and re-create the database schema on startup -->

                   <property name="hbm2ddl.auto">create</property>

                   <!-- <mapping class="cc.tukai.entity.Student"/> -->

                   <mapping resource="cc/tukai/entity/Student.hbm.xml"/>

         </session-factory>

</hibernate-configuration>


测试类Test

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

import cc.tukai.entity.Student;

public class Test {

         @org.junit.Test

         public void testSave() {

                   Student student = new Student();

                   student.setAge(20);

                   student.setName("test");

                   SessionFactory factory = new Configuration().configure()

                                     .buildSessionFactory();

                   Session session = factory.openSession();

                   session.beginTransaction();

                   session.save(student);

                   session.getTransaction().commit();

                   session.close();

                   factory.close();

         }

运行一下我们的测试类,查看一下数据库

hibernate5_id生成策略

由上图我们可以看到hibernate已经为我们创建了student表,并且主键id为varchar(255)类型,生成的值也是一个字符串。


举例说明native

现在我们将生成策略改为native,那就要将原来的Student.hbm.xml中的    <generator class="uuid"></generator>改为         <generator class="native"></generator>

由于对于mysql而言,native是根据 auto_increment来生成主键的值的,所以要将实体类的id从刚刚的String类型改为int类型。好的,改完之后将原来数据库中的 Student表删除掉,因为hibernate识别不了类型改变,所以他不会帮你重新建表。这个时候就可以重新运行我们原来的测试类了。

下面为测试类运行完产生的结果:

hibernate5_id生成策略

下面我们用Annotation来操作一下上面的例子
对于jpa有四种id生成策略:

1.默认为auto

I.对于mysql而言为auto_increment

II.对于oracle而言为sequence

2.identity

3.sequence

4.table

现在我们更改一下上面例子中的代码

Student类

package cc.tukai.entity;

import java.io.Serializable;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

@Entity

@Table(name = "Student")

public class Student implements Serializable {

         private static final long serialVersionUID = -5596241291862147220L;

         private int id;

         private String name;

         private int age;

         @Id

         @GeneratedValue(strategy = GenerationType.AUTO)

         public int getId() {

                   return id;

         }

         public void setId(int id) {

                   this.id = 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;

         }

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

         <session-factory>

                   <!-- Database connection settings -->

                   <property name="connection.driver_class">com.mysql.jdbc.Driver</property>

                   <property name="connection.url">jdbc:mysql://127.0.0.1/hibernate</property>

                   <property name="connection.username">root</property>

                   <property name="connection.password">1234</property>

                   <!-- SQL dialect -->

                   <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

                   <!-- Echo all executed SQL to stdout -->

                   <property name="show_sql">true</property>

                   <!-- Drop and re-create the database schema on startup -->

                   <property name="hbm2ddl.auto">create</property>

                   <mapping class="cc.tukai.entity.Student" />

                  <!--<mapping resource="cc/tukai/entity/Student.hbm.xml"/> -->

         </session-factory>

</hibernate-configuration>

测试类Test

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

import cc.tukai.entity.Student;

public class Test {

         @org.junit.Test

         public void testSave() {

                   Student student = new Student();

                   student.setAge(20);

                   student.setName("test");

                   SessionFactory factory = new Configuration().configure()

                                     .buildSessionFactory();

                   Session session = factory.openSession();

                   session.beginTransaction();

                   session.save(student);

                   session.getTransaction().commit();

                   session.close();

                   factory.close();

         }

运行完后的结果:

hibernate5_id生成策略

注:

对于oracle而言,hibernate默认会为我们创建一个sequence,然而默认每张表用的都是这一个sequence。这里补充一下指定sequence的方法。

首先要在类的前面添加

@SequenceGenerator(name = "生成器的名字",sequenceName=”数据库中sequence的名字")

在@GeneratedValue的中添加generator="生成器的名字"

hibernate5_id生成策略

table生成策略

如果你想将你的程序能够真正意义上的跨数据库平台,那hibernate为我们提供了一种id的生成策略――Table,当然这种情况是很少用的,毕竟现在写程序一般是不会要求我们跨数据库平台的。

下面我们就这种策略来说明一下他的配置:

在类的前面添加

@javax.persistence.TableGenerator(

name="生成器的名称",

table="数据库表名",

pkColumnName = "表的字段名",

valueColumnName = "表的值名称"

pkColumnValue="字段的值",

allocationSize=每次的步长

在id的get方法前添加

@GeneratedValue(strategy = GenerationType.TABLE,generator="生成器的名字")

对于Table这种id生成器策略的意思是通过表来获取id的值,首先他会将预定的值保存到数据库中,默认为1,举个例子说明一下吧:如果我定义 tableGenerator的数据库表名为Student_generator,pkColumnName为 PK_Key,valueColumnName为PK_Value,pkColumnValue为Student,allocationSize为1,这个时候hibernate会先建一张Student_generator表,这张表有两个字段,一个是类型为varchar(255),字段名为 PK_Key,一个是类型为int(11),字段名为PK_Value,首先会插入一个值为(Student,1),但我们插入数据时,而这个数据的id 生成策略为上面的这个策略,那hibernate首先会执行:select PK_Value from student_generator where PK_Key这条语句,然后取出这个值作为id的值,之后将PK_Value的值改为原来的值加上步长,这个新产生的值作为下一个需要这个id的值。这中方式可以跨任何的数据库,并且一个数据库表可以保存所有的表中要用到的id。

  
联合主键

一般我们设计数据库的时候尽量不要使用联合主键,但怕的就是我们现在接手的是一个遗留的项目,人家设计的时候就是用的联合主键,遇到这样的项目那我们怎样用hibernate去映射这个联合主键呢?

如上面中我们经常说到的Student类,假如现在我们要将原来的id和name做为联合主键,那该怎么配置呢?

作为面向对象的设计,这样的情况我们一般会新建一个类作为主键类,也就是我们要新建一个类,比如说Student_PK,里面有id和name这两个属性。当然这个类我们要重写他的equals,hashcode方法,以及要去实现java.io.Serializable接口。为什么要去重写这些方法,主要是因为他是主键我们必须要让他唯一,为什么要实现java.io.Serializable接口,是因为在项目中可能会出现内存不够的情况,那这样的话就要将内存里面的对象写到硬盘中,所以就必须要实现这个接口。

这样我们将主键作为了一个类,那我们本来的Student类中就不要有id和name属性了,那就用主键类来代替了。

Student.java

package cc.tukai.entity;

import java.io.Serializable;

import javax.persistence.Entity;

import javax.persistence.Table;

@Entity

@Table(name = "Student")

public class Student implements Serializable {

    private static final long serialVersionUID = -5596241291862147220L;

    private Student_PK pk;

    private int age;

    public Student_PK getPk() {

       return pk;

    }

    public void setPk(Student_PK pk) {

       this.pk = pk;

    }

    public int getAge() {

       return age;

    }

    public void setAge(int age) {

       this.age = age;

    }

Student_PK

package cc.tukai.entity;

import java.io.Serializable;

public class Student_PK implements Serializable {

    private static final long serialVersionUID = 1334477470452734661L;

    private int id;

    private String name;

    public int getId() {

       return id;

    }

    public void setId(int id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    @Override

    public int hashCode() {

       final int prime = 31;

       int result = 1;

       result = prime * result + id;

       result = prime * result + ((name == null) ? 0 : name.hashCode());

       return result;

    }

    @Override

    public boolean equals(Object obj) {

       if (this == obj)

           return true;

       if (obj == null)

           return false;

       if (getClass() != obj.getClass())

           return false;

       Student_PK other = (Student_PK) obj;

       if (id != other.id)

           return false;

       if (name == null) {

           if (other.name != null)

              return false;

       } else if (!name.equals(other.name))

           return false;

       return true;

    }

Student.hbm.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 package="cc.tukai.entity">

    <class name="Student" table="student">

       <composite-id name="pk" class="Student_PK">

           <key-property name="id"></key-property>

           <key-property name="name"></key-property>

       </composite-id>

       <property name="age" type="java.lang.Integer">

           <column name="age" length="10"></column>

       </property>

    </class>

</hibernate-mapping>

Test.java

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

import cc.tukai.entity.Student;

import cc.tukai.entity.Student_PK;

public class Test {

         @org.junit.Test

         public void testSave() {

                   Student_PK pk=new Student_PK();

                   pk.setName("test");

                   pk.setId(1);

                   Student student = new Student();

                   student.setAge(20);

                   student.setPk(pk);

                   SessionFactory factory = new Configuration().configure()

                                     .buildSessionFactory();

                   Session session = factory.openSession();

                   session.beginTransaction();

                   session.save(student);

                   session.getTransaction().commit();

                   session.close();

                   factory.close();

         }

运行完测试类之后的结果:

hibernate5_id生成策略

由上图就可以看出id和name都为主键了。

用Annotation的方法配置联合主键

用Annotation的方法配置联合主键,管方提供了三种方法。

1.将组件类注解为@Embeddable,并将组件的属性注解为@Id

就是将Student_PK这个类注解为@Embeddable,并且将Student的getPK方法注解为@Id

2.将组件的属性注解为@EmbeddableId">2.将组件的属性注解为@EmbeddableId

在Student的getPK方法注解为@EmbeddableId

3.将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id

将 Student类中依旧添加id和name这两个属性,并且将这两个属性的get方法都注解为@Id,然后在Student类中添加 @IdClass(Student_PK.class)">然后在Student类中添加@IdClass(Student_PK.class)。


分享到:
评论

相关推荐

    Hibernate教程02_ID生成策略

    http://blog.csdn.net/e421083458/article/details/8794127 该源码为Hibernate教程配套源码

    JAVA 的ID生成策略

    主要描述hibernate在Annotation情况下的主键生成策略

    Hibernate的主键生成策略

    Hibernate的所有自带的主键生成策略以及XML配置文件的用法

    JPA学习笔记-EJB-03JPA主键生成策略总结

    第一种单字段主键类型,看上去简单,无非就是一个id字段呗,实际上这个主键字段在JPA,还有任何的ORM框架中都是有很多种生成策略的。 一般是如下4种: 1. AUTO:自动自增生成 2. TABLE:自定义表生成器 3. Identity...

    auto-factory-0.1-beta1.zip

    postgres-hibernate-mapper.zip,Postgre Hibernate Mapper是处理默认Hibernate ID生成策略的小项目。Postgre-Hibernate-Mapper是解决此问题的小项目...

    Hibernate笔记 马士兵

    第13课 ID主键生成策略 20 一、 Xml方式 20 元素(主键生成策略) 20 二、 annotateon方式 21 1、AUTO默认 21 2、IDENTITY 22 3、SEQUENCE 22 4、为Oracle指定定义的Sequence 22 5、TABLE - 使用表保存id值 23 三、 ...

    马士兵hibernate学习笔记(原版)

    5 ID生成策略(重点 AUTO) 6 Hibernate核心开发接口介绍(重点) ... 风格 1 先脉络,后细节 2 先操作,后原理 3 重Annotation,轻xml配置文件 ... 性能优化 1 注意session.clear()的运用,尤其在不断...

    Hibernate注解

    * @GenericGenerator —— 注解声明了一个hibernate的主键生成策略。支持十三种策略。该注解有如下属性 * name 指定生成器名称 * strategy 指定具体生成器的类名(指定生成策略)。 * parameters 得到strategy指定的...

    Hibernate+中文文档

    3.8. Hibernate SQL方言 (hibernate.dialect) 3.9. Hibernate日志类别 3.10. JTA TransactionManagers 9.1. 继承映射特性(Features of inheritance mappings) 16.1. 别名注射(alias injection names) 19.1. ...

    hibernate配置

    hibernate是一个封装在SQL和JDBC之上的企业级应用框架 配置文件的基本结构如下: &lt;?xml version="1.0" encoding='UTF-8'?&gt;... 主键生成策略"/&gt; &lt;/id&gt; …… &lt;/hibernate-mapping&gt;

    Hibernate注释大全收藏

    @Id 注解可将实体Bean中某个属性定义为主键,使用@GenerateValue注解可以定义该标识符的生成策略。 • AUTO - 可以是 identity column, sequence 或者 table 类型,取决于不同底层的数据库 • TABLE - 使用table...

    Hibernate中的merge使用详情解说.docx

    merge的作用是:新new一个对象,如果该对象设置了ID,则这个对象就当作游离态处理: 当ID在数据库中不能找到时,用...用update的话,由于没有ID,所以会报异常,merge此时则会保存数据,根据ID生产策略生成一条数据;

    hibernate3.2中文文档(chm格式)

    HIBERNATE - 符合Java习惯的关系数据库持久化 Hibernate参考文档 3.2 -------------------------------------------------------------------------------- 目录 前言 1. 翻译说明 2. 版权声明 1. Hibernate...

    HibernateAPI中文版.chm

    HIBERNATE - 符合Java习惯的关系数据库持久化 Hibernate参考文档 3.2 -------------------------------------------------------------------------------- 目录 前言 1. 翻译说明 2. 版权声明 1. Hibernate...

    hibernate 教程

    开始Hibernate之旅 1.2. 第一个可持久化类 1.3. 映射cat 1.4. 与猫同乐 1.5. 结语 2. 体系结构 2.1. 总览 2.2. JMX集成 2.3. JCA支持 3. SessionFactory配置 3.1. 可编程配置方式...

    hibernate课程详解

    hibernate相关知识,包括关系映射、缓存配置、id生成策略等

    hibernate笔记

    5 ID生成策略(重点 AUTO) 5 6 Hibernate核心开发接口介绍(重点) 5 7 对象的三种状态(了解) 5 8 关系映射(重点) 5 9 Hibernate査询(HQL) 5 10 在Struts基础上继续完善BBS200 5 11 性能优化(重点) 5 12 补充...

    hibernate学习笔记

    Hibernate 学习笔记 Hibernate 学习笔记 1 第一个hibernate项目(hibernate_first) 2 测试实体对象的生命周期(hibernate_session) 3 ...hibernate抓取策略 53 Hibernate最佳实践(Best Practices) 55

    演示怎样在Hibernate中使用复合主键

    那么,我们这里的解决方案是使用uuid.hex生成32个字符长度的ITEM_ID订单编号,然后CATEGORY_ITEM表根据这个订单编号来追加业务逻辑数据。 使用方式: 1、下载解压之后,使用MyEclipse导入工程 2、使用查询分析,把...

    HibernateForeignKeyGenerator:演示如何在Hibernate Framework中使用“外国”生成器策略。 以及如何定义一对一关系

    演示如何使用Hibernate生成器“ Foreign”关键策略和一对一映射。 介绍如何使用Hibernate和spring在内存嵌入式db中使用H2。 给您有关创建定制生成器的想法。TechStack。 Spring Core / ORM。 Hibernate框架。 ...

Global site tag (gtag.js) - Google Analytics