`
lushuaiyin
  • 浏览: 704931 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

uuid.hex主键生成器

 
阅读更多


对于数据库主键生成策略,大家都了解一些,尤其是关于hibernate的主键生成更是方便很多。

而大多数人只知道使用,hibernate给定的生成策略,我今天想说的是主键生成器,就是自己写一个类来生成主键。

在开始之前,先对hibernate给定的生成策略做个了解。



**************************************************************************************************

1 assigned:主键由外部程序负责生成,无需hibernate参与。特点是:主键的生成完全由用户决定,与底层数据库无关,用户需要维护主键值,并且要在session.save()之前指定主键值,否则会抛出异常。

2 hilo:通过hilo算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态。使用高低位算法生成主键,高低位算法使用一个高位值和一个低位值,然后把算法得到的两个值拼接起来作为数据库中的唯一主键。默认情况下采用的表是hibernate_unique_key。

3 seqhilo:与hilo类似,通过hilo算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库

4 increment:主键按数值顺序递增。当HIbernate准备在数据库中插入一条记录时,首先从数据库表中取出当前主键字段的最大值,然后在最大值的基础上加1,作为当前持久化对象的标识符属性值。这种方式可能产生的问题是:如果当前有多个实例访问数据库,那么由于各个实例各自维持着主键状态,不同实例可能生成相同的主键,从而造成主键重复异常。

5 identity:采用数据库提供的主键生成机制

6 sequence:采用数据库提供的sequence生成主键,要设定序列名 <param name="sequence">name_seq</param>。如果未指定序列名,则hibernate默认使用名为“hibernate_sequence"的序列

7 native:有Hibernate根据地层数据库自行判断采用identity,hilo,sequence中一种作为主键生成机制

8 uuid.hex:由hibernate基于128位唯一值产生算法生成十六进制数值作为主键

9 uuid.string:与uuid.hex相似,只是生成的主键没有进行编码(16位),在某些数据库中可能出现问题

10 foreign:使用外部表的字段作为主键

11 select:使用触发器生成主键

**************************************************************************************************

现在我想说的是UUID主键生成。

在hibernate的映射文件中,配置成<generator class="uuid"/>就可以直接使用了。

关于它,要知道几点知识:


一、用一个128-bit的UUID算法生成字符串类型的标识符。

二、在一个网络中唯一(生成算法使用了IP地址)。

三、UUID被编码为一个32位16进制数字的字符串。


好了,现在我们想自己写一个UUID主键生成器该怎么办呢?

其实很简单,既然Hibernate已经帮我们写好了,我们就可以看看它的源码怎么写的,单独把相关代码摘出来就可以了。


在hibernate3.jar中,UUIDHexGenerator

/*jadclipse*/// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.

package org.hibernate.id;

import java.io.PrintStream;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.Hibernate;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type;
import org.hibernate.util.PropertiesHelper;

// Referenced classes of package org.hibernate.id:
//            AbstractUUIDGenerator, Configurable, IdentifierGenerator

public class UUIDHexGenerator extends AbstractUUIDGenerator
    implements Configurable
{

    public UUIDHexGenerator()
    {
        sep = "";
    }

    protected String format(int intval)
    {
        String formatted = Integer.toHexString(intval);
        StringBuffer buf = new StringBuffer("00000000");
        buf.replace(8 - formatted.length(), 8, formatted);
        return buf.toString();
    }

    protected String format(short shortval)
    {
        String formatted = Integer.toHexString(shortval);
        StringBuffer buf = new StringBuffer("0000");
        buf.replace(4 - formatted.length(), 4, formatted);
        return buf.toString();
    }

    public Serializable generate(SessionImplementor session, Object obj)
    {
        return (new StringBuffer(36)).append(format(getIP())).append(sep).append(format(getJVM())).append(sep).append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep).append(format(getCount())).toString();
    }

    public void configure(Type type, Properties params, Dialect d)
    {
        sep = PropertiesHelper.getString("separator", params, "");
    }

    public static void main(String args[])
        throws Exception
    {
        Properties props = new Properties();
        props.setProperty("separator", "/");
        IdentifierGenerator gen = new UUIDHexGenerator();
        ((Configurable)gen).configure(Hibernate.STRING, props, null);
        IdentifierGenerator gen2 = new UUIDHexGenerator();
        ((Configurable)gen2).configure(Hibernate.STRING, props, null);
        for(int i = 0; i < 10; i++)
        {
            String id = (String)gen.generate(null, null);
            System.out.println(id);
            String id2 = (String)gen2.generate(null, null);
            System.out.println(id2);
        }

    }

    private String sep;
}


/*
	DECOMPILATION REPORT

	Decompiled from: D:\ChinaDevelopmentBankJBPM\workSpace\frame\webapp\WEB-INF\lib\hibernate3.jar
	Total time: 195 ms
	Jad reported messages/errors:
	Exit status: 0
	Caught exceptions:
*/

这个类继承了AbstractUUIDGenerator

/*jadclipse*/// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.

package org.hibernate.id;

import java.net.InetAddress;
import org.hibernate.util.BytesHelper;

// Referenced classes of package org.hibernate.id:
//            IdentifierGenerator

public abstract class AbstractUUIDGenerator
    implements IdentifierGenerator
{

    public AbstractUUIDGenerator()
    {
    }

    protected int getJVM()
    {
        return JVM;
    }

    protected short getCount()
    {
        Class class1 = org.hibernate.id.AbstractUUIDGenerator.class;
        JVM INSTR monitorenter ;
        if(counter < 0)
            counter = 0;
        return counter++;
        Exception exception;
        exception;
        throw exception;
    }

    protected int getIP()
    {
        return IP;
    }

    protected short getHiTime()
    {
        return (short)(int)(System.currentTimeMillis() >>> 32);
    }

    protected int getLoTime()
    {
        return (int)System.currentTimeMillis();
    }

    private static final int IP;
    private static short counter = 0;
    private static final int JVM = (int)(System.currentTimeMillis() >>> 8);

    static 
    {
        int ipadd;
        try
        {
            ipadd = BytesHelper.toInt(InetAddress.getLocalHost().getAddress());
        }
        catch(Exception e)
        {
            ipadd = 0;
        }
        IP = ipadd;
    }
}


/*
	DECOMPILATION REPORT

	Decompiled from: D:\ChinaDevelopmentBankJBPM\workSpace\frame\webapp\WEB-INF\lib\hibernate3.jar
	Total time: 156 ms
	Jad reported messages/errors:
Overlapped try statements detected. Not all exception handlers will be resolved in the method getCount
Couldn't fully decompile method getCount
Couldn't resolve all exception handlers in method getCount
	Exit status: 0
	Caught exceptions:
*/

要想摘出来代码,要明白:继承的父类是必须要摘的,而接口我们完全可以忽略。

再把父类中的方法摘出放到子类中去,这样这个父类也没有利用价值了。

到此基本上快完成了,对于几个出错的方法,我们尽可能注释掉,最后不出错,写个main方法测试一下。



这是最后摘出来整合好的UUIDHexGenerator

package org.base.pk;

import java.io.Serializable;
import java.net.InetAddress;


public class UUIDHexGenerator {

	public UUIDHexGenerator() {
		sep = "";
	}

	protected String format(int intval) {
		String formatted = Integer.toHexString(intval);
		StringBuffer buf = new StringBuffer("00000000");
		buf.replace(8 - formatted.length(), 8, formatted);
		return buf.toString();
	}

	protected String format(short shortval) {
		String formatted = Integer.toHexString(shortval);
		StringBuffer buf = new StringBuffer("0000");
		buf.replace(4 - formatted.length(), 4, formatted);
		return buf.toString();
	}

	public Serializable generate() {
		return (new StringBuffer(36)).append(format(getIP())).append(sep)
				.append(format(getJVM())).append(sep)
				.append(format(getHiTime())).append(sep)
				.append(format(getLoTime())).append(sep)
				.append(format(getCount())).toString();
	}

	

	private String sep;

	// /////////////////

	protected int getJVM() {
		return JVM;
	}

	protected short getCount() {
		Class class1 = org.base.pk.UUIDHexGenerator.class;
		if (counter < 0)
			counter = 0;
		return counter++;
	}

	protected int getIP() {
		return IP;
	}

	protected short getHiTime() {
		return (short) (int) (System.currentTimeMillis() >>> 32);
	}

	protected int getLoTime() {
		return (int) System.currentTimeMillis();
	}

	private static final int IP;
	private static short counter = 0;
	private static final int JVM = (int) (System.currentTimeMillis() >>> 8);

	static {
		int ipadd;
		try {
			ipadd = toInt(InetAddress.getLocalHost().getAddress());
		} catch (Exception e) {
			ipadd = 0;
		}
		IP = ipadd;
	}
	public static int toInt(byte bytes[])
    {
        int result = 0;
        for(int i = 0; i < 4; i++)
            result = ((result << 8) - -128) + bytes[i];

        return result;
    }
	
	
	public static void main(String args[]) throws Exception {
		UUIDHexGenerator gen = new UUIDHexGenerator();
		for (int i = 0; i < 10; i++) {
			String id = (String) gen.generate();
			System.out.println(id);
		}

	}
}

运行一下,打印:

8ab78fab3cf123ac013cf123acb00000
8ab78fab3cf123ac013cf123acb10001
8ab78fab3cf123ac013cf123acb10002
8ab78fab3cf123ac013cf123acb10003
8ab78fab3cf123ac013cf123acb10004
8ab78fab3cf123ac013cf123acb10005
8ab78fab3cf123ac013cf123acb10006
8ab78fab3cf123ac013cf123acb10007
8ab78fab3cf123ac013cf123acb10008
8ab78fab3cf123ac013cf123acb10009


到此为止,还不算大功告成,毕竟这是一个主键生成器,算是工具类了。

我们要把这个类改成静态的,使用起来才算方便。

改变时注意变量sep要赋值空字符串,否则这个变量始终是null。

这是最终版的UUID主键生成器

package org.base.pk;

import java.io.Serializable;
import java.net.InetAddress;


public class UUIDHexGenerator {

	public UUIDHexGenerator() {}

	public static String format(int intval) {
		String formatted = Integer.toHexString(intval);
		StringBuffer buf = new StringBuffer("00000000");
		buf.replace(8 - formatted.length(), 8, formatted);
		return buf.toString();
	}

	public static String format(short shortval) {
		String formatted = Integer.toHexString(shortval);
		StringBuffer buf = new StringBuffer("0000");
		buf.replace(4 - formatted.length(), 4, formatted);
		return buf.toString();
	}

	public static Serializable generate() {
		return (new StringBuffer(36)).append(format(getIP())).append(sep)
				.append(format(getJVM())).append(sep)
				.append(format(getHiTime())).append(sep)
				.append(format(getLoTime())).append(sep)
				.append(format(getCount())).toString();
	}

	

	public static String sep="";

	// /////////////////

	public static int getJVM() {
		return JVM;
	}

	public static short getCount() {
		Class class1 = org.base.pk.UUIDHexGenerator.class;
		if (counter < 0)
			counter = 0;
		return counter++;
	}

	public static int getIP() {
		return IP;
	}

	public static short getHiTime() {
		return (short) (int) (System.currentTimeMillis() >>> 32);
	}

	public static int getLoTime() {
		return (int) System.currentTimeMillis();
	}

	private static final int IP;
	private static short counter = 0;
	private static final int JVM = (int) (System.currentTimeMillis() >>> 8);

	static {
		int ipadd;
		try {
			ipadd = toInt(InetAddress.getLocalHost().getAddress());
		} catch (Exception e) {
			ipadd = 0;
		}
		IP = ipadd;
	}
	public static int toInt(byte bytes[])
    {
        int result = 0;
        for(int i = 0; i < 4; i++)
            result = ((result << 8) - -128) + bytes[i];

        return result;
    }
	
	
	public static void main(String args[]) throws Exception {
		for (int i = 0; i < 10; i++) {
			String id = (String) UUIDHexGenerator.generate();
			System.out.println(id);
		}

	}
}

运行后打印:

8ab78fab3cf12cc3013cf12cc4020000
8ab78fab3cf12cc3013cf12cc4020001
8ab78fab3cf12cc3013cf12cc4020002
8ab78fab3cf12cc3013cf12cc4020003
8ab78fab3cf12cc3013cf12cc4020004
8ab78fab3cf12cc3013cf12cc4020005
8ab78fab3cf12cc3013cf12cc4020006
8ab78fab3cf12cc3013cf12cc4020007
8ab78fab3cf12cc3013cf12cc4020008
8ab78fab3cf12cc3013cf12cc4030009

大功告成。


1 assigned:主键由外部程序负责生成,无需hibernate参与。特点是:主键的生成完全由用户决定,与底层数据库无关,用户需要维护主键值,并且要在session.save()之前指定主键值,否则会抛出异常。

2 hilo:通过hilo算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态。使用高低位算法生成主键,高低位算法使用一个高位值和一个低位值,然后把算法得到的两个值拼接起来作为数据库中的唯一主键。默认情况下采用的表是hibernate_unique_key。

3 seqhilo:与hilo类似,通过hilo算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库

4 increment:主键按数值顺序递增。当HIbernate准备在数据库中插入一条记录时,首先从数据库表中取出当前主键字段的最大值,然后在最大值的基础上加1,作为当前持久化对象的标识符属性值。这种方式可能产生的问题是:如果当前有多个实例访问数据库,那么由于各个实例各自维持着主键状态,不同实例可能生成相同的主键,从而造成主键重复异常。

5 identity:采用数据库提供的主键生成机制

6 sequence:采用数据库提供的sequence生成主键,要设定序列名 <param name="sequence">name_seq</param>。如果未指定序列名,则hibernate默认使用名为“hibernate_sequence"的序列

7 native:有Hibernate根据地层数据库自行判断采用identity,hilo,sequence中一种作为主键生成机制

8 uuid.hex:由hibernate基于128位唯一值产生算法生成十六进制数值作为主键

9 uuid.string:与uuid.hex相似,只是生成的主键没有进行编码(16位),在某些数据库中可能出现问题

10 foreign:使用外部表的字段作为主键

11 select:使用触发器生成主键

分享到:
评论

相关推荐

    Hibernate内置标识符生成器

    7. UUID(Universally Unique Identifier)生成器:Hibernate 提供了两种 UUID 生成器,`uuid.hex` 和 `uuid.string`。这两种生成器使用 128 位的 UUID 算法,生成全局唯一的标识符。`uuid.hex` 生成的是 32 位的...

    Hibernate主键生成

    主键生成器确保了每个记录都有一个独一无二的标识,这对于数据的完整性至关重要。以下是Hibernate中常见的主键生成方式及其特点: 1. **increment**:此策略对long、short或int类型的字段生成自动增长的主键。主键...

    Hibernate主键类型说明和配置手册.doc

    1. **uuid.hex**: 这种生成器使用128位算法生成一个32位的字符串。由于其通用性,它适用于所有类型的数据库。在`.hbm.xml`映射文件中,你可以这样配置: ```xml &lt;generator class="uuid.hex"/&gt; ``` 2. **...

    Hibernate映射文件主键的生成

    在Hibernate中,主键的生成可以通过编程方式、数据库内置机制或者特定的生成器来实现。接下来我们将逐一探讨这些策略: 1. **Identity策略**: 这种策略适用于支持自动增长主键的数据库,如MySQL的`AUTO_INCREMENT...

    hibernate映射文件的详解

    4. 主键生成器(Key Generator):用于决定如何生成对象的唯一标识(主键)。`Assigned`表示主键由程序员手动管理,`hilo`和`seqhilo`使用hi/lo算法,适用于需要高效主键生成的场景,但可能需要额外的数据库表或序列...

    hibernate的映射文件配置

    除了内置的主键生成策略,开发者还可以通过扩展Hibernate的类来自定义主键生成器。这允许更灵活地控制主键的生成逻辑,满足特定业务场景的需求。具体实现细节可参考相关文档或社区资源。 总之,Hibernate映射文件的...

    hibernate。hbm.xml配置详解

    - `uuid.hex`: 128 位 UUID 转换为 16 进制字符串。 - `uuid.string`: 未经编码的 UUID 字符串,不适用于 PostgreSQL。 - `foreign`: 使用关联对象的标识符作为主键。 例如,使用 `native` 策略的主键配置如下: `...

    解决sql server保存对象字符串转换成uniqueidentifier失败的问题

    在Hibernate映射文件中,ID的生成策略设置为`uuid.hex`,这意味着在持久化对象时,会尝试将一个由`uuid.hex`生成的16进制字符串转换为`uniqueidentifier`,导致了错误。 解决这个问题的方法是将映射文件中的ID生成...

    hibernate-mapping参数详解

    7. `key-generator`:主键生成器,用于定义如何生成数据库主键。常见的选项有: - `assigned`:主键由应用程序自己生成。 - `hilo`、`seqhilo`:基于hi/lo算法,适用于需要高效主键生成的场景。 - `increment`:...

    oracle的配置文件

    如上文所述,Hibernate提供了多种主键生成策略,包括assigned、hilo、seqhilo、increment、identity、sequence、native、uuid.hex、uuid.string以及foreign,每种策略适应不同的场景和数据库特性。 例如,如果在...

    ssh 框架整合总结

    主键生成机制在Hibernate中至关重要,因为它确保了数据的唯一性。包括assigned(外部生成)、hilo、seqhilo、increment、identity、sequence、native、uuid.hex、uuid.string和foreign等多种方式,每种都有其适用...

    XDoclet Tags

    4. **@generator-class**: 如果在`@id`中使用了自定义的主键生成器,此标签用于指定生成器的类全名。 5. **@property**: 用于定义实体类的属性,与数据库中的列相对应。可以设置`column`属性来指定列名,`type`属性...

    STRUTS+SPRING+HIBERNATE

    - `&lt;id&gt;` 标签定义了主键的映射关系,使用 `uuid.hex` 生成器自动生成主键值。 - `&lt;property&gt;` 标签定义了类属性与数据库字段的映射关系。 ##### 2. 构建脚本 build.xml 构建脚本主要用于自动化构建过程,例如编译...

    美国硅谷SVSE软件工程教育Hibernate-Lesson2

    主键生成策略包括assigned、hilo、seqhilo、increment、identity、sequence、native、uuid.hex和foreign,根据不同的数据库特性和需求选择合适的策略。 - **复合主键映射**:当需要多个字段共同构成主键时,可以...

    Hibernate框架详细讲解

    2. **提高开发效率**:Hibernate提供了多种自动化工具,如代码生成器等,可以自动生成部分代码,大大加快了开发速度。 3. **跨数据库平台支持**:由于其强大的映射功能,Hibernate能够轻松地在不同的数据库之间切换...

    Hibernate Tutorial 03 (Object Identifier).pdf

    对于某些类型的数据库(如HSQLDB),可以使用序列/生成器来生成这个序列号。这种策略被称为“sequence”。由于单个持久化对象不能拥有多个标识符,我们需要将ISBN字段改为普通属性,并在数据库表中添加非空和唯一...

    hibernate说明文档

    - **uuid.hex**: 采用128位UUID算法生成标识符,虽然保证了全局唯一性,但可能因存储开销较大而不推荐作为主键。 通过理解这些配置元素和属性,开发者可以更有效地使用Hibernate进行数据库操作,实现高效的数据持久...

    hibernate配置详解

    - `uuid.hex`:使用128位的UUID生成策略。 - `assigned`:手动分配。 - `&lt;property&gt;`:定义属性映射。 - `name`:指定Java属性名称。 - `type`:指定属性类型。 - `&lt;column&gt;`:同上。 3. **其他配置**: - `...

Global site tag (gtag.js) - Google Analytics