Hibernate 中 UUID.HEX的实现机制??
Hibernate主键生成方式KeyGenerator
主键产生器
可选项说明:
1)assigned
主键由外部程序负责生成,无需Hibernate参与。
2)hilo
通过hi/lo算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态。
3)seqhilo
与hilo类似,通过hi/lo算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库,如Oracle。
4)increment
主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候
将此值加1作为主键。
这种方式可能产生的问题是:如果当前有多个实例访问同一个数据库,那么由于各个实例各自维护主键状态,不同实例可能生成同样的主键,从而造成主键重复异常。因此,如果同一数据库有多个实例访问,此方式必须避免使用。
5)identity
采用数据库提供的主键生成机制。如DB2、SQLServer、MySQL中的主键生成机制。
6)sequence
采用数据库提供的sequence机制生成主键。如Oralce中的Sequence。
7)native
由Hibernate根据底层数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式。
8)uuid.hex
由Hibernate基于128位唯一值产生算法生成16进制数值(编码后以长度32的字符串表示)作为主键。
9)uuid.string
与uuid.hex类似,只是生成的主键未进行编码(长度16)。在某些数据库中可能出现问题(如PostgreSQL)。
10)foreign
使用外部表的字段作为主键。
一般而言,利用uuid.hex方式生成主键将提供最好的性能和数据库平台适应性。
另外由于常用的数据库,如Oracle、DB2、SQLServer、MySql等,都提供了易用的主键生成机制(Auto-Increase字段或者Sequence)。我们可以在数据库提供的主键生成机制上,采用generator-class=native的主键生成方式。不过值得注意的是,一些数据库提供的主键生成机制在效率上未必最佳,大量并发insert数据时可能会引起表之间的互锁。
数据库提供的主键生成机制,往往是通过在一个内部表中保存当前主键状态(如对于自增型主键而言,此内部表中就维护着当前的最大值和递增量),之后每次插入数据会读取这个最大值,然后加上递增量作为新记录的主键,之后再把这个新的最大值更新回内部表中,这样,一次Insert操作可能导致数据库内部多次表读写操作,同时伴随的还有数据的加锁解锁操作,这对性能产生了较大影响。
因此,对于并发Insert要求较高的系统,推荐采用uuid.hex作为主键生成机制。
在Hibernate中主键的生成方式中有一种是UUID.HEX方式。
它是Hibernate系统自动生成一个32位长的字符串。
具体的使用方法是:修改hbm.xml主键的默认的手动生成方式<generatorclass="assigned"/>为<generatorclass="uuid.hex"/>
如下是两个示例:
<idname="userid"type="java.lang.String">
<columnname="USERID"length="20"/>
<generatorclass="uuid.hex"/>
</id>
<idname="empno"type="java.lang.String">
<columnname="EMPNO"length="50"/>
<generatorclass="uuid.hex"></generator>
</id>
我试着使用这种方法向数据库中插入了几条记录,得到的主键(32位字符串)如下:
402852432955363a012955363c110001
40285243295535a301295535a6980001
40285243295418b801295418bac60001
40285243295535e801295535ea770001
说到32位字符,我很自然的想到了php中的加密运算算法md5()。
下面是一些字符md5加密之后的结果:
a6907acf5b337a322193f19b6698c867(jia)
d3d9446802a44259755d38e6d163e820(10)
c02d0450cdd75ce7595f5eaeb5f041a3(7988)
d603f7ff967282ff491e956b21f10a6c(c02d0450cdd75ce7595f5eaeb5f041a3)
9825f096ee35843407c643a5af383ab0(d603f7ff967282ff491e956b21f10a6c)
如下是php中测试的代码:
echo"jia"."==========".md5(jia)."<br>";
echo"jia"."==========".md5("jia")."<br>";
echo"10"."==========".md5("10")."<br>";
echo"10"."==========".md5(10)."<br>";
echo"7988"."==========".md5(7988)."<br>";
echo"c02d0450cdd75ce7595f5eaeb5f041a3"."==========
".md5(c02d0450cdd75ce7595f5eaeb5f041a3)."<br>";
echo"d603f7ff967282ff491e956b21f10a6c"."==========
".md5(d603f7ff967282ff491e956b21f10a6c)."<br>";
UUID.HEX中使用某种算法生成了32位“无意义的”、“原理上不应该重复的字符”。我一直疑心它可能是把一些有序的数字(可以理解为序列)通过md5(或者是类似md5的算法,……应该就是md5,不应该有别的方法了)算法,装换为一些表面上无意义的字符(仔细看一下这些连续插入的主键,他们还是有些规律,至少前面几位还是相同的)。但这些字符作为主键来使用一定是不重复的(这是由数据库中主键的特征决定的)。一些表面上看起来是无意义的字符,同时还要确保他们的唯一性,目前谁能做到这一点?我想也只有md5了…………
查了一下资料:在Java中是提供了加密算法的
MessageDigestmd=MessageDigest.getInstance("MD5");
但是Java中的md5加密要自己去实现一些方法,对于同一个字符在Java中加密后的结果和在php中md5()加密后的结果是不同的……
c02d0450cdd75ce7595f5eaeb5f041a3(7988)phpmd5()
2d0450cdd75ce7595f5eaeb5f041a3(7988)
/*
java.security
类MessageDigest
java.lang.Object
java.security.MessageDigestSpi
java.security.MessageDigest
*/
//packagecom.tsinghua;
importjava.security.*;
publicclassMD5Tool{
//主方法
publicstaticvoidmain(String[]args){
Stringtest="7988";
//创建一个MD5Tool类
MD5ToolmyMd5=newMD5Tool();
//调用MD5Encrypt(StringinStr)方法
Stringresult=myMd5.MD5Encrypt(test);
//打印结果
System.out.println(test+"加密後的结果是:"+result);
}
//该方法将你输入的字符串,通过md5加密,返回一个加密後的字符串
publicstaticStringMD5Encrypt(StringinStr){
MessageDigestmd=null;
StringoutStr=null;
try{
md=MessageDigest.getInstance("MD5");//可以选中其他的算法如SHA
byte[]digest=md.digest(inStr.getBytes());
//返回的是byet[],要转化为String存储比较方便
//调用bytetoString(byte方法,返回一个输出结果
outStr=bytetoString(digest);
}
catch(NoSuchAlgorithmExceptionnsae){
nsae.printStackTrace();
}
returnoutStr;
}
//
publicstaticStringbytetoString(byte[]digest){
Stringstr="";
StringtempStr="";
for(inti=1;i<digest.length;i++){
tempStr=(Integer.toHexString(digest[i]&0xff));
if(tempStr.length()==1){
str=str+"0"+tempStr;
}
else{
str=str+tempStr;
}
}
returnstr.toLowerCase();
}
}
所有的<generator>的Class都是从net.sf.hibernate.id.IdentifierGenerator接口实现得到的,Class属性表示该generator是由哪种方式来生成的。生成方式包括:
increment:生成long,short或者int类型的主键,不能在cluster环境下使用。适用于所有数据库
identity:生成long,short或者int类型的主键。适用于DB2,MySQL,MSSQLServer,SybaseandHypersonicSQL
sequence:生成long,short或者int类型的主键。适用于DB2,PostgreSQL,Oracle,SAPDB,McKoi,Interbase.
hilo:生成long,short或者int类型的主键。需要提供一个数据库的表来存放生成的主键信息。当采用应用服务器的JTA提供的数据库连接或者用户自定义的数据库连接的时候,不要使用这种主键生成方式。适用于所有数据库
seqhilo:采用给定的数据库的sequence来生成long,short或者int类型的主键。适用于DB2,PostgreSQL,Oracle,SAPDB,McKoi,Interbase.
uuid.hex:采用128位的算法来生成一个32位字符串。最通用的一种方式。适用于所有数据库
uuid.string:同样采用128位的UUID算法。将生成的字符编码位16位。适用于除PostgreSQL.以外的数据库
native:根据具体连接的数据库从identity,sequence或者hilo选择一种来生成主键。适用的数据库根据选择的生成方式确定。
assigned:交给应用自己给主键赋值。要注意的是赋值必须在调用save()方法之前完成。适用的数据库根据选择的生成方式确定。