UUID生成

 

      关于UUID的标准参考->http://en.wikipedia.org/wiki/Universally_unique_identifier,JAVA1.7 JDK支持其中version3(基于名称)和version4(随机)的UUID生成方式。

Version3

      Version 3 UUIDs use a scheme deriving a UUID via MD5 from a URL, a fully qualified domain name, an object identifier, a distinguished name (DN as used in Lightweight Directory Access Protocol), or on names in unspecified namespaces. Version 3 UUIDs have the form xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B.

Version4

       Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the version number (4 bits) as well as two reserved bits. All other bits (the remaining 122 bits) are set using a random or pseudorandom data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B (e.g., f47ac10b-58cc-4372-a567-0e02b2c3d479).

       Version4是基于随机数字生成的UUID,因为没有那么大的数据量无法测试生成UUID是否是绝对唯一的,因此考虑使用Version3生成UUID。以下代码也适用于不同机器集群中生成UUID。为了减少UUID生成的时间,可以一次生成多个UUID,并存放到一个UUID缓存中。

package com.company.projects.gis.md5;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.UUID;
/**
 * 采用MD5加密解密
 * @author tfq
 * @datetime 2011-10-13
 */
public class UUIDUtil {
	public static long seed = 0 ;
	
	private static String mac = "" ; 
	
	static{
		//获取mac地址
		try {
			NetworkInterface networkInterface = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
			byte[] macByte = networkInterface.getHardwareAddress() ;
			StringBuffer sb = new StringBuffer("");
			for(int i=0; i<macByte.length; i++) {
				if(i!=0) {
					sb.append("-");
				}
				//字节转换为整数
				String str = Integer.toHexString(macByte[i]&0xff);
				if(str.length()==1) {
					sb.append("0"+str);
				}else {
					sb.append(str);
				}
			}
			//设置mac地址
			mac = sb.toString() ;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 根据mac地址、时间和seed生成UUID,生成UUID是经过MD5加密过的,能够避免生成id连续的UUID
	 * @return
	 */
	public synchronized static String getUUID(){
		if(seed > Long.MAX_VALUE){
			seed = Long.MIN_VALUE  ;
		}
		++seed ;
		UUID uuid = UUID.nameUUIDFromBytes((mac+(System.currentTimeMillis())+seed).getBytes()) ;
		return uuid.toString() ;
	}
	// 测试主函数
	public static void main(String args[]) throws UnknownHostException, SocketException {
		for (int i = 0; i < 10; i++) {
			System.out.println(getUUID());
		}
	}
}

hibernate生成uuid

      hibernate提供了多种生成唯一主键标识的方式,其中包括uuid,uuid是由IP+JVM启动时间+当前时间+计数标识来生成的。可以在多机分布式集群和单机集群中生成uuid,Hibernate中生成uuid的类为org.hibernate.id.UUIDHexGenerator。

 

另参考一种生成有意义的uuid方式。参考地址:http://825635381.iteye.com/blog/2295479

       相对于DB自增序列的全局主键生成器,性能更高,同时保留业务需求的业务含义, 
对于有分库分表需求的业务同时可以存储分库和分表的信息,对于高并发的互联网企业分库分表生成主键来说是一种很好的方法 

Java代码   收藏代码
  1. package com.tongbanjie.trade.test.base;  
  2.   
  3. import java.net.InetAddress;  
  4. import org.apache.commons.lang.StringUtils;  
  5. import com.tongbanjie.commons.util.TSS;  
  6.   
  7. public class TestGenId {  
  8.       
  9.     public static void main(String[] args) throws Exception {  
  10.           
  11.         /** 
  12.          * 项目:交易单分表 
  13.          *  
  14.          *  需求 
  15.          *  查询需求: 1. userId维度 
  16.          *           2. 产品维度 
  17.          *           3. 商户维度 
  18.          *           4. 时间区间维度 
  19.          *   
  20.          *  预计订单量: 
  21.          *        一单平均10000, 一年交易额5000亿, 需要成功订单量 = 500000000000 / 10000 = 50000000 5000万订单 
  22.          *       购买加回款应该是1亿订单量, 所以, 单表2000万, 一年需要5张表 
  23.          *   
  24.          *      最后扩展64库 + 64表, 共64*64 = 4096表, 4096 * 2000万 = 819亿订单够用了, 819亿 * 10000 = 8190000亿  819万亿,够用了 
  25.          *   
  26.          *  全局唯一主键: 
  27.          *      15位时间戳 + 自增序号四位 + 机器后两段IP,6位 + 备用1位 + 分库信息两位 + 分表信息两位  共30位,  回款改造前 
  28.          *      15位时间戳 + 自增序号四位 + 机器后两段IP,6位 + 备用3位 + 分库信息两位 + 分表信息两位  共32位,  回款改造后 
  29.          *       
  30.          *      单JVM支持最多1s  1000 * 9999 = 9999000, 999万9千笔订单,后续还可以扩展。 
  31.          *   
  32.          *  分库规则: 
  33.          *      寻找到数据库  (userId/100) % 64 + 1 找到数据库    订单最多64个库    目前一个库   二分法裂变扩容 
  34.          *  分表规则: 
  35.          *      寻找到表信息  userId % 64 + 1 找到表信息    一个库最多64个表   目前分8张表    以后二分法裂变扩容 
  36.          *   
  37.          *  迁移规则: 
  38.          *      迁移方案同步写, 目前用动态表名, 以后分表中间件稳定后, 迁移过去 
  39.          *   
  40.          *  查询改造: 
  41.          *      原接口不变,对用户无感知, 底层钩子遍历 
  42.          */  
  43.   
  44.         // 只获取本地局域网IP即可  
  45.         String ip = InetAddress.getLocalHost().getHostAddress();  
  46.         String[] ipArray = ip.split("\\.");  
  47.   
  48.         final String lastTwoPhaseIp = StringUtils.rightPad(ipArray[2], 3'0')  
  49.                 + StringUtils.leftPad(ipArray[3], 3'0');  
  50.           
  51.         for (int i = 0; i < 100000; i++) {  
  52.             new Thread(new Runnable() {  
  53.                   
  54.                 @Override  
  55.                 public void run() {  
  56.                     // TSS commons工具类  
  57.                     String tss = TSS.getTimeStampSequence();  
  58.                     String id = tss + lastTwoPhaseIp + "000" + "01" + "08";  
  59.                     System.out.println(id);  
  60.                 }  
  61.             }).start();  
  62.         }  
  63.     }  
  64.       
  65. }  

 

Java代码   收藏代码
  1. package com.tongbanjie.commons.util;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5. import java.util.concurrent.ConcurrentHashMap;  
  6. import java.util.concurrent.atomic.AtomicInteger;  
  7.   
  8. import org.apache.commons.lang.StringUtils;  
  9.   
  10. /** 
  11.  * 时间戳序列器<br> 
  12.  *  
  13.  * 支持同一毫秒最多生成9999笔序列号<br> 
  14.  * @author sanfeng 
  15.  * 
  16.  * 想象力就是生产力 
  17.  */  
  18. public class TSS {  
  19.   
  20.     // 默认1个大小  
  21.     private static ConcurrentHashMap<String, AtomicInteger> cache = new ConcurrentHashMap<String, AtomicInteger>(1);  
  22.           
  23.     public static String getTimeStampSequence() {  
  24.           
  25.         String timestamp = new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date());  
  26.           
  27.         String inc = null;  
  28.           
  29.         AtomicInteger value = cache.get(timestamp);  
  30.           
  31.         if(value == null) {  
  32.             cache.clear();  
  33.             int defaultStartValue = 0;  
  34.             cache.put(timestamp, new AtomicInteger(defaultStartValue));  
  35.             inc = String.valueOf(defaultStartValue);  
  36.         } else {  
  37.             inc = String.valueOf(value.addAndGet(1));  
  38.         }  
  39.           
  40.         return timestamp + StringUtils.leftPad(inc, 4'0');  
  41.     }  
  42.   
  43. }  

      关于UUID的标准参考->http://en.wikipedia.org/wiki/Universally_unique_identifier,JAVA1.7 JDK支持其中version3(基于名称)和version4(随机)的UUID生成方式。

Version3

      Version 3 UUIDs use a scheme deriving a UUID via MD5 from a URL, a fully qualified domain name, an object identifier, a distinguished name (DN as used in Lightweight Directory Access Protocol), or on names in unspecified namespaces. Version 3 UUIDs have the form xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B.

Version4

       Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the version number (4 bits) as well as two reserved bits. All other bits (the remaining 122 bits) are set using a random or pseudorandom data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B (e.g., f47ac10b-58cc-4372-a567-0e02b2c3d479).

       Version4是基于随机数字生成的UUID,因为没有那么大的数据量无法测试生成UUID是否是绝对唯一的,因此考虑使用Version3生成UUID。以下代码也适用于不同机器集群中生成UUID。为了减少UUID生成的时间,可以一次生成多个UUID,并存放到一个UUID缓存中。

package com.company.projects.gis.md5;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.UUID;
/**
 * 采用MD5加密解密
 * @author tfq
 * @datetime 2011-10-13
 */
public class UUIDUtil {
	public static long seed = 0 ;
	
	private static String mac = "" ; 
	
	static{
		//获取mac地址
		try {
			NetworkInterface networkInterface = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
			byte[] macByte = networkInterface.getHardwareAddress() ;
			StringBuffer sb = new StringBuffer("");
			for(int i=0; i<macByte.length; i++) {
				if(i!=0) {
					sb.append("-");
				}
				//字节转换为整数
				String str = Integer.toHexString(macByte[i]&0xff);
				if(str.length()==1) {
					sb.append("0"+str);
				}else {
					sb.append(str);
				}
			}
			//设置mac地址
			mac = sb.toString() ;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 根据mac地址、时间和seed生成UUID,生成UUID是经过MD5加密过的,能够避免生成id连续的UUID
	 * @return
	 */
	public synchronized static String getUUID(){
		if(seed > Long.MAX_VALUE){
			seed = Long.MIN_VALUE  ;
		}
		++seed ;
		UUID uuid = UUID.nameUUIDFromBytes((mac+(System.currentTimeMillis())+seed).getBytes()) ;
		return uuid.toString() ;
	}
	// 测试主函数
	public static void main(String args[]) throws UnknownHostException, SocketException {
		for (int i = 0; i < 10; i++) {
			System.out.println(getUUID());
		}
	}
}

hibernate生成uuid

      hibernate提供了多种生成唯一主键标识的方式,其中包括uuid,uuid是由IP+JVM启动时间+当前时间+计数标识来生成的。可以在多机分布式集群和单机集群中生成uuid,Hibernate中生成uuid的类为org.hibernate.id.UUIDHexGenerator。

 

另参考一种生成有意义的uuid方式。参考地址:http://825635381.iteye.com/blog/2295479

       相对于DB自增序列的全局主键生成器,性能更高,同时保留业务需求的业务含义, 
对于有分库分表需求的业务同时可以存储分库和分表的信息,对于高并发的互联网企业分库分表生成主键来说是一种很好的方法 

Java代码   收藏代码
  1. package com.tongbanjie.trade.test.base;  
  2.   
  3. import java.net.InetAddress;  
  4. import org.apache.commons.lang.StringUtils;  
  5. import com.tongbanjie.commons.util.TSS;  
  6.   
  7. public class TestGenId {  
  8.       
  9.     public static void main(String[] args) throws Exception {  
  10.           
  11.         /** 
  12.          * 项目:交易单分表 
  13.          *  
  14.          *  需求 
  15.          *  查询需求: 1. userId维度 
  16.          *           2. 产品维度 
  17.          *           3. 商户维度 
  18.          *           4. 时间区间维度 
  19.          *   
  20.          *  预计订单量: 
  21.          *        一单平均10000, 一年交易额5000亿, 需要成功订单量 = 500000000000 / 10000 = 50000000 5000万订单 
  22.          *       购买加回款应该是1亿订单量, 所以, 单表2000万, 一年需要5张表 
  23.          *   
  24.          *      最后扩展64库 + 64表, 共64*64 = 4096表, 4096 * 2000万 = 819亿订单够用了, 819亿 * 10000 = 8190000亿  819万亿,够用了 
  25.          *   
  26.          *  全局唯一主键: 
  27.          *      15位时间戳 + 自增序号四位 + 机器后两段IP,6位 + 备用1位 + 分库信息两位 + 分表信息两位  共30位,  回款改造前 
  28.          *      15位时间戳 + 自增序号四位 + 机器后两段IP,6位 + 备用3位 + 分库信息两位 + 分表信息两位  共32位,  回款改造后 
  29.          *       
  30.          *      单JVM支持最多1s  1000 * 9999 = 9999000, 999万9千笔订单,后续还可以扩展。 
  31.          *   
  32.          *  分库规则: 
  33.          *      寻找到数据库  (userId/100) % 64 + 1 找到数据库    订单最多64个库    目前一个库   二分法裂变扩容 
  34.          *  分表规则: 
  35.          *      寻找到表信息  userId % 64 + 1 找到表信息    一个库最多64个表   目前分8张表    以后二分法裂变扩容 
  36.          *   
  37.          *  迁移规则: 
  38.          *      迁移方案同步写, 目前用动态表名, 以后分表中间件稳定后, 迁移过去 
  39.          *   
  40.          *  查询改造: 
  41.          *      原接口不变,对用户无感知, 底层钩子遍历 
  42.          */  
  43.   
  44.         // 只获取本地局域网IP即可  
  45.         String ip = InetAddress.getLocalHost().getHostAddress();  
  46.         String[] ipArray = ip.split("\\.");  
  47.   
  48.         final String lastTwoPhaseIp = StringUtils.rightPad(ipArray[2], 3'0')  
  49.                 + StringUtils.leftPad(ipArray[3], 3'0');  
  50.           
  51.         for (int i = 0; i < 100000; i++) {  
  52.             new Thread(new Runnable() {  
  53.                   
  54.                 @Override  
  55.                 public void run() {  
  56.                     // TSS commons工具类  
  57.                     String tss = TSS.getTimeStampSequence();  
  58.                     String id = tss + lastTwoPhaseIp + "000" + "01" + "08";  
  59.                     System.out.println(id);  
  60.                 }  
  61.             }).start();  
  62.         }  
  63.     }  
  64.       
  65. }  

 

Java代码   收藏代码
  1. package com.tongbanjie.commons.util;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5. import java.util.concurrent.ConcurrentHashMap;  
  6. import java.util.concurrent.atomic.AtomicInteger;  
  7.   
  8. import org.apache.commons.lang.StringUtils;  
  9.   
  10. /** 
  11.  * 时间戳序列器<br> 
  12.  *  
  13.  * 支持同一毫秒最多生成9999笔序列号<br> 
  14.  * @author sanfeng 
  15.  * 
  16.  * 想象力就是生产力 
  17.  */  
  18. public class TSS {  
  19.   
  20.     // 默认1个大小  
  21.     private static ConcurrentHashMap<String, AtomicInteger> cache = new ConcurrentHashMap<String, AtomicInteger>(1);  
  22.           
  23.     public static String getTimeStampSequence() {  
  24.           
  25.         String timestamp = new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date());  
  26.           
  27.         String inc = null;  
  28.           
  29.         AtomicInteger value = cache.get(timestamp);  
  30.           
  31.         if(value == null) {  
  32.             cache.clear();  
  33.             int defaultStartValue = 0;  
  34.             cache.put(timestamp, new AtomicInteger(defaultStartValue));  
  35.             inc = String.valueOf(defaultStartValue);  
  36.         } else {  
  37.             inc = String.valueOf(value.addAndGet(1));  
  38.         }  
  39.           
  40.         return timestamp + StringUtils.leftPad(inc, 4'0');  
  41.     }  
  42.   
  43. }  

猜你喜欢

转载自lpyyn.iteye.com/blog/2108263