Java中生成唯一ID的方法示例
有时我们不依赖于数据库中自动递增的字段产生唯一ID,比如多表同一字段需要统一一个唯一ID,这时就需要用程序来生成一个唯一的全局ID。
UUID
从Java5开始,UUID类提供了一种生成唯一ID的简单方法。UUID是通用唯一识别码(UniversallyUniqueIdentifier)的缩写,UUID来源于OSF(OpenSoftwareFoundation,开源软件基金会)的DCE(DistributedComputingEnvironment,分布式计算环境)规范。UUID的目的,是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。如此一来,每个人都可以建立不与其它人冲突的UUID。
UUID是一个128bit的数字,也可以表现为32个16进制的字符(每个字符0-F的字符代表4bit),中间用"-"分割。
- 时间戳+UUID版本号:分三段占16个字符(60bit+4bit),
- ClockSequence号与保留字段:占4个字符(13bit+3bit),
- 节点标识:占12个字符(48bit),
UUID的唯一缺陷在于生成的结果串会比较长。
publicclassGenerateUUID{ publicstaticfinalvoidmain(String...args){ //generaterandomUUIDs UUIDidOne=UUID.randomUUID(); UUIDidTwo=UUID.randomUUID(); log("UUIDOne:"+idOne); log("UUIDTwo:"+idTwo); } privatestaticvoidlog(Objectobject){ System.out.println(String.valueOf(object)); } }
结果为
UUIDOne:6b193443-b95d-4462-9902-a6455ebc56d6
UUIDTwo:4ef9b375-839b-4150-8f31-1ed85fab63fd
随机数的哈希值
此方法使用SecureRandom和MessageDigest:
- 启动时,初始化SecureRandom(这可能是一个冗长的操作)
- 使用SecureRandom生成一个随机数
- 创建一个MessageDigest,使用某种摘要算法
- 将MessageDigest返回的byte[]编码为某种可接受的文本形式
- 检查结果是否已经被使用;如果尚未使用,则适合作为唯一标识符
MessageDigest类是适合于产生任意数据的“单向散列”。
publicclassGenerateId{ publicstaticvoidmain(String...arguments){ try{ SecureRandomprng=SecureRandom.getInstance("SHA1PRNG"); StringrandomNum=Integer.valueOf(prng.nextInt()).toString(); MessageDigestsha=MessageDigest.getInstance("SHA-1"); byte[]result=sha.digest(randomNum.getBytes()); System.out.println("Randomnumber:"+randomNum); System.out.println("Messagedigest:"+hexEncode(result)); }catch(NoSuchAlgorithmExceptionex){ System.err.println(ex); } } staticprivateStringhexEncode(byte[]input){ StringBuilderresult=newStringBuilder(); char[]digits={'0','1','2','3','4','5','6','7','8','9','a', 'b','c','d','e','f'}; for(intidx=0;idx>4]); result.append(digits[b&0x0f]); } returnresult.toString(); } }
结果为
Randomnumber:-2017013782
Messagedigest:2c3bba8d4dbd3699648c5909685d21f9c64b6a8a
Twitter的snowflake
twitter的一个全局唯一id生成器,结果是一个long型的ID。
- 正数位(1bit):一个符号位,永远是0。
- 时间戳(41bit):自从2012年以来的毫秒数,能撑139年。
- 自增序列(12bit,最大值4096):毫秒之内的自增,过了一毫秒会重新置0。
- DataCenterID(5bit,最大值32):配置值,支持多机房。
- WorkerID(5bit,最大值32),配置值,一个机房里最多32个机器。
Snowflake算法的变化
Snowflake算法生成的唯一ID为long型数值,但如果想在应用中使用int类型的自增ID的话可以做些调整。
时间戳改为分钟(25bit),自增序列(7bit)。自增序列最大值128,在一分钟内会不够使用。可以采用预支方式取下一分钟。
此方式只适用于一个单体应用,不适合分布式系统。
/** *@ClassName:SnowflakeIdWorker3rd *@Description:snowflake算法改进 *@author:wanghao *@date:2019年12月13日下午12:50:47 *@versionV1.0 * *将产生的Id类型更改为Integer32bit
*把时间戳的单位改为分钟,使用25个比特的时间戳(分钟)
*去掉机器ID和数据中心ID
*7个比特作为自增值,即2的7次方等于128。 */ publicclassSnowflakeIdWorker3rd{ /**开始时间戳(2019-01-01)*/ privatefinalinttwepoch=25771200;//1546272000000L/1000/60; /**序列在id中占的位数*/ privatefinallongsequenceBits=7L; /**时间截向左移7位*/ privatefinallongtimestampLeftShift=sequenceBits; /**生成序列的掩码,这里为127*/ privatefinalintsequenceMask=-1^(-1<counter.get()){ counter.set(timestamp); isAdvance=false; } //如果是同一时间生成的,则进行分钟内序列 if(lastTimestamp==timestamp||isAdvance){ if(!isAdvance){ sequence=(sequence+1)&sequenceMask; } //分钟内自增列溢出 if(sequence==0){ //预支下一个分钟,获得新的时间戳 isAdvance=true; intlaterTimestamp=counter.get(); if(laterSequence==0){ laterTimestamp=counter.incrementAndGet(); } intnextId=((laterTimestamp-twepoch)< publicclassMinuteCounter{ privatestaticfinalintMASK=0x7FFFFFFF; privatefinalAtomicIntegeratom; publicMinuteCounter(){ atom=newAtomicInteger(0); } publicfinalintincrementAndGet(){ returnatom.incrementAndGet()&MASK; } publicintget(){ returnatom.get()&MASK; } publicvoidset(intnewValue){ atom.set(newValue&MASK); } }到此这篇关于Java中生成唯一ID的方法示例的文章就介绍到这了,更多相关Java生成唯一ID内容请搜素毛票票以前的文章或下面相关文章,希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。