`

扩展hibernate的主键生成策略

    博客分类:
  • Java
阅读更多
Hibernate的主键生成策略有好几种:
1) assigned
2) hilo
3) seqhilo
4) increment
5) identity
6) sequence
7) native
8) uuid.hex
9) uuid.string
10) foreign
一般而言,利用uuid.hex方式生成主键将提供最好的性能和数据库平台适
应性。另外由于常用的数据库,如Oracle、DB2、SQLServer、MySql 等,都提
供了易用的主键生成机制(Auto-Increase 字段或者Sequence)。我们可以在数
据库提供的主键生成机制上,采用generator-class=native的主键生成方式。
不过值得注意的是,一些数据库提供的主键生成机制在效率上未必最佳,
大量并发insert数据时可能会引起表之间的互锁。
数据库提供的主键生成机制,往往是通过在一个内部表中保存当前主键状
态(如对于自增型主键而言,此内部表中就维护着当前的最大值和递增量),
之后每次插入数据会读取这个最大值,然后加上递增量作为新记录的主键,之
后再把这个新的最大值更新回内部表中,这样,一次Insert操作可能导致数据
库内部多次表读写操作,同时伴随的还有数据的加锁解锁操作,这对性能产生
了较大影响。
因此,对于并发Insert要求较高的系统,推荐采用uuid.hex 作为主键生成
机制。
另外我们可以扩展Hibernate的类来做自己的主键生成策略:
java 代码
 
  1. package com.gsta.eshore.framework.util.uid;  
  2. import java.io.Serializable;  
  3. import org.hibernate.engine.SessionImplementor;  
  4. import org.hibernate.id.AbstractUUIDGenerator;  
  5. import org.hibernate.id.Configurable;  
  6. import org.hibernate.id.IdentifierGenerator;  
  7. import java.util.Properties;  
  8. import org.hibernate.Hibernate;  
  9. import org.hibernate.dialect.Dialect;  
  10. import org.hibernate.type.Type;  
  11. import org.hibernate.util.PropertiesHelper;  
  12. /** 
  13.  * <b>uuid</b><br> 
  14. * @author hwq 
  15.  */  
  16. public class UIDGenerator extends AbstractUUIDGenerator implements Configurable {  
  17.     private static long lastTime = System.currentTimeMillis();  
  18.     private static short lastCount = -32768;  
  19.     private static Object mutex = new Object();  
  20.     private static long ONE_SECOND = 1000L;  
  21.     private String sep = "";  
  22.     public Serializable generate(SessionImplementor session, Object obj) {  
  23.         long l = 0L;  
  24.         short word0 = 0;  
  25.         int i = 0;  
  26.         synchronized(mutex)  
  27.         {  
  28.             if(lastCount == 32767)  
  29.             {  
  30.                 for(boolean flag = false; !flag;)  
  31.                 {  
  32.                     l = System.currentTimeMillis();  
  33.                     if(l < lastTime + ONE_SECOND)  
  34.                     {  
  35.                         try  
  36.                         {  
  37.                             Thread.currentThread();  
  38.                             Thread.sleep(ONE_SECOND);  
  39.                         }  
  40.                         catch(InterruptedException interruptedexception) { }  
  41.                     } else  
  42.                     {  
  43.                         lastTime = l;  
  44.                         lastCount = -32768;  
  45.                         flag = true;  
  46.                     }  
  47.                 }  
  48.             } else  
  49.             {  
  50.                 l = lastTime;  
  51.             }  
  52.             word0 = lastCount++;  
  53.             i = getHostUniqueNum();  
  54.         }  
  55.         String s = Integer.toString(i, 16) + sep + Long.toString(l, 16) + sep + Integer.toString(word0, 16);  
  56.         if(s.length() > 24)  
  57.             s = s.substring(s.length() - 24);  
  58.         return s;  
  59.     }  
  60.     public Serializable generate_old(SessionImplementor session, Object obj) {  
  61.         String name = obj.getClass().getName();  
  62.         return new StringBuffer(64)  
  63.             .append(name.substring(name.lastIndexOf('.')+1)).append(sep)  
  64.             .append((short)getIP()).append(sep)  
  65.             .append(Math.abs((short)getJVM())).append(sep)  
  66.             .append(getCount())   
  67.             .toString();  
  68.     }  
  69.     private static int getHostUniqueNum()  
  70.     {  
  71.         return (new Object()).hashCode();  
  72.     }  
  73.     public void configure(Type type, Properties params, Dialect d) {  
  74.         sep = PropertiesHelper.getString("separator", params, "");  
  75.     }  
  76.     public static void main( String[] args ) throws Exception {  
  77.         Properties props = new Properties();  
  78.         props.setProperty("separator""");  
  79.         IdentifierGenerator gen = new UIDGenerator();  
  80.         ( (Configurable) gen ).configure(Hibernate.STRING, props, null);  
  81.         IdentifierGenerator gen2 = new UIDGenerator();  
  82.         ( (Configurable) gen2 ).configure(Hibernate.STRING, props, null);  
  83.         for ( int i=0; i<10; i++) {  
  84.             String id = (String) gen.generate(null, gen);  
  85.             System.out.println(id);  
  86.             String id2 = (String) gen2.generate(null, gen2);  
  87.             System.out.println(id2);  
  88.         }  
  89.     }  
  90. }  
这个类必须要扩展AbstractUUIDGenerator并实现Configurable接口,在generate方法中生成我们想要的主键。
在hibernate的配置文件中要做以下的配置:
xml 代码
 
  1. <id name="id" type="java.lang.String">  
  2.       <column name="id" length="24" />  
  3.       <generator class="com.gsta.eshore.framework.util.uid.UIDGenerator"><param name="separator">-</param></generator>  
  4.   </id>  
Generator的类要引用UIDGenerator,并且可以带参数生成主键,示例是根据时间,Ip等生成一个24位的字符串。这样做的灵活性大大提高了,提供了最好的性能和数据库平台适应性。
但是有时候我们在保存一条记录的时候是不能指定主键的,因为它的主键要来源于其他的表的主键,(hibernate推荐用代理主键,但是有时候设计的时候没有用到)。这个时候的主键生成策略就要是assigned了。为了保持主键的连贯性,我总不能又用另外一种主键生成策略吧。
仿照上面的类,我们做一个生成24为随机字符串的类。
java 代码
 
  1. package com.gsta.eshore.framework.util.uid;  
  2. public class UID  
  3. {  
  4.     private static long lastTime = System.currentTimeMillis();  
  5.     private static short lastCount = -32768;  
  6.     private static Object mutex = new Object();  
  7.     private static long ONE_SECOND = 1000L;  
  8.     public UID()  
  9.     {  
  10.     }  
  11.     public static String getUID()  
  12.     {  
  13.         long l = 0L;  
  14.         short word0 = 0;  
  15.         int i = 0;  
  16.         synchronized(mutex)  
  17.         {  
  18.             if(lastCount == 32767)  
  19.             {  
  20.                 for(boolean flag = false; !flag;)  
  21.                 {  
  22.                     l = System.currentTimeMillis();  
  23.                     if(l < lastTime + ONE_SECOND)  
  24.                     {  
  25.                         try  
  26.                         {  
  27.                             Thread.currentThread();  
  28.                             Thread.sleep(ONE_SECOND);  
  29.                         }  
  30.                         catch(InterruptedException interruptedexception) { }  
  31.                     } else  
  32.                     {  
  33.                         lastTime = l;  
  34.                         lastCount = -32768;  
  35.                         flag = true;  
  36.                     }  
  37.                 }  
  38.             } else  
  39.             {  
  40.                 l = lastTime;  
  41.             }  
  42.             word0 = lastCount++;  
  43.             i = getHostUniqueNum();  
  44.         }  
  45.         String s = Integer.toString(i, 16) + "`" + Long.toString(l, 16) + "`" + Integer.toString(word0, 16);  
  46.         if(s.length() > 24)  
  47.             s = s.substring(s.length() - 24);  
  48.         return s;  
  49.     }  
  50.     private static int getHostUniqueNum()  
  51.     {  
  52.         return (new Object()).hashCode();  
  53.     }  
  54.   
  55.    public static void main(String[] args) {  
  56.         for (int i = 0; i < 100; i++) {  
  57.             String uid=getUID();  
  58.             System.out.println(uid);  
  59.         }  
  60.         }  
  61. }  
在save一个实体的时候调用entity.setId(UID.getUID())。
呵呵,以后用hibernate就不用烦用什么主键生成策略了,自己做一个。
<id name="id" type="java.lang.String"><column name="id" length="24"><id type="java.lang.String" name="id"><column length="24" name="id"></id></column></id>
分享到:
评论

相关推荐

    HQL学习教程Hibernate入門

    HQL Hibernate入門 java 时间日期的方法大全讲解 扩展hibernate的主键生成策略

    Hibernate注解

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

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     5.1.2 Hibernate访问持久化类属性的策略  5.1.3 在持久化类的访问方法中加入程序逻辑  5.1.4 设置派生属性  5.1.5 控制insert和update语句  5.2 处理SQL引用标识符  5.3 创建命名策略  5.4 设置数据库Schema...

    Hibernate实战(第2版 中文高清版)

    第一部分 从Hibernate和EJB 3.0开始  第1章 理解对象/关系持久化   1.1 什么是持久化   1.1.1 关系数据库   1.1.2 理解SQL   1.1.3 在Java中使用SQL   1.1.4 面向对象应用程序中的持久化   1.2 范式不...

    Hibernate 中文 html 帮助文档

    触发器实现的主键生成器(Primary keys assigned by triggers) 5.1.5. composite-id 5.1.6. 鉴别器(discriminator) 5.1.7. 版本(version)(可选) 5.1.8. timestamp (可选) 5.1.9. property 5.1.10. 多对一...

    精通hibernate:对象持久化技术孙卫琴第二版part2

    本章主要介绍关系数据库中的代理主键(不具有业务含义),接着介绍Hibernate提供的几种内置标识符生成器的用法及适用范围。 6.1 关系数据库按主键区分不同的记录 123 6.1.1 把主键定义为自动增长标识符类型 123 ...

    Hibernate注释大全收藏

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

    hibernate 体系结构与配置 参考文档(html)

    触发器实现的主键生成器(Primary keys assigned by triggers) 5.1.5. composite-id 5.1.6. 鉴别器(discriminator) 5.1.7. 版本(version)(可选) 5.1.8. timestamp (可选) 5.1.9. property 5.1.10. 多对...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

     5.1.2 Hibernate访问持久化类属性的策略  5.1.3 在持久化类的访问方法中加入程序逻辑  5.1.4 设置派生属性  5.1.5 控制insert和update语句  5.2 处理SQL引用标识符  5.3 创建命名策略  5.4 设置数据库Schema...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

     5.1.2 Hibernate访问持久化类属性的策略  5.1.3 在持久化类的访问方法中加入程序逻辑  5.1.4 设置派生属性  5.1.5 控制insert和update语句  5.2 处理SQL引用标识符  5.3 创建命名策略  5.4 设置数据库Schema...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

     5.1.2 Hibernate访问持久化类属性的策略  5.1.3 在持久化类的访问方法中加入程序逻辑  5.1.4 设置派生属性  5.1.5 控制insert和update语句  5.2 处理SQL引用标识符  5.3 创建命名策略  5.4 设置数据库Schema...

    精通Hibernate:对象持久化技术第二版part3

    本章主要介绍关系数据库中的代理主键(不具有业务含义),接着介绍Hibernate提供的几种内置标识符生成器的用法及适用范围。 6.1 关系数据库按主键区分不同的记录 123 6.1.1 把主键定义为自动增长标识符类型 123 ...

    Hibernate参考文档

    触发器实现的主键生成器(Primary keys assigned by triggers) 5.1.5. composite-id 5.1.6. 鉴别器(discriminator) 5.1.7. 版本(version)(可选) 5.1.8. timestamp (可选) 5.1.9. property 5.1.10. 多对一...

    Java面试宝典2020修订版V1.0.1.doc

    目录 ... 11 2、CSS样式定义优先级顺序是?...20、Hibernate的主键生成策略? 94 21、Hibernate的级联操作 94 22、Hibernate有哪5个核心接口? 95 23、什么是重量级?什么是轻量级? 95 24、谈谈Spring的IOC和DI

    Spring中文帮助文档

    11.5.2. 使用SimpleJdbcInsert来获取自动生成的主键 11.5.3. 指定SimpleJdbcInsert所使用的字段 11.5.4. 使用SqlParameterSource提供参数值 11.5.5. 使用SimpleJdbcCall调用存储过程 11.5.6. 声明SimpleJdbcCall...

    Spring API

    11.5.2. 使用SimpleJdbcInsert来获取自动生成的主键 11.5.3. 指定SimpleJdbcInsert所使用的字段 11.5.4. 使用SqlParameterSource提供参数值 11.5.5. 使用SimpleJdbcCall调用存储过程 11.5.6. 声明SimpleJdbcCall...

Global site tag (gtag.js) - Google Analytics