全局唯一主键生成器

来源:互联网 发布:win8.1一键优化工具 编辑:程序博客网 时间:2024/05/16 18:58
全局主键生成器 

介绍: 
相对于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 org.apache.commons.lang.StringUtils;  
  4.   
  5. import java.io.BufferedReader;  
  6. import java.io.FileInputStream;  
  7. import java.io.InputStreamReader;  
  8. import java.text.SimpleDateFormat;  
  9. import java.util.Date;  
  10. import java.util.HashMap;  
  11. import java.util.HashSet;  
  12. import java.util.concurrent.atomic.AtomicInteger;  
  13. import java.util.concurrent.locks.ReentrantLock;  
  14.   
  15. /** 
  16.  * 时间戳序列器<br> 
  17.  *  
  18.  * 支持同一毫秒最多生成9999笔序列号<br> 
  19.  * @author sanfeng 
  20.  * 
  21.  * 想象力就是生产力 
  22.  */  
  23. public class TSS {  
  24.   
  25.     // 默认1个大小  
  26.     private static HashMap<String, AtomicInteger> tssCache  
  27.         = new HashMap<String, AtomicInteger>(1);  
  28.       
  29.     private static final ReentrantLock lock = new ReentrantLock();  
  30.   
  31.     // 因为有锁,所以是变成了线程安全的,省去每次 new 的消耗,耗时降低约一半  
  32.     private static final SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmssSSS");  
  33.       
  34.     public static String getTimeStampSequence() {  
  35.           
  36.         String timestamp = null;  
  37.         String inc = null;  
  38.           
  39.         lock.lock();  
  40.         try {  
  41.               
  42.             timestamp = sdf.format(new Date());  
  43.             AtomicInteger value = tssCache.get(timestamp);  
  44.             if(value == null) {  
  45.                 tssCache.clear();  
  46.                 int defaultStartValue = 0;  
  47.                 tssCache.put(timestamp, new AtomicInteger(defaultStartValue));  
  48.                 inc = String.valueOf(defaultStartValue);  
  49.             } else {  
  50.                 inc = String.valueOf(value.addAndGet(1));  
  51.             }  
  52.         } finally {  
  53.             lock.unlock();  
  54.         }  
  55.           
  56.         return timestamp + StringUtils.leftPad(inc, 4'0');  
  57.     }  
  58.   
  59.       
  60.     public static void main(String[] args) throws Exception {  
  61.           
  62. //      for (int i = 0; i < 1000; i++) {  
  63. //          new Thread(new Runnable() {  
  64. //                
  65. //              @Override  
  66. //              public void run() {  
  67. //                  for (int j = 0; j < 10; j++) {  
  68. //                      System.out.println(TSS.getTimeStampSequence());  
  69. //                  }  
  70. //              }  
  71. //          }).start();  
  72. //      }  
  73.   
  74.           
  75.         // 统计重复  
  76.         HashSet<String> set = new HashSet<String>();  
  77.         BufferedReader br = new BufferedReader(  
  78.                 new InputStreamReader(new FileInputStream("C:/Users/Administrator/Desktop/1.txt")));  
  79.         String str = br.readLine();  
  80.         while(str != null) {  
  81.             if(set.contains(str)) {  
  82.                 System.out.println(str);  
  83.             } else {  
  84.                 set.add(str);  
  85.             }  
  86.             str = br.readLine();  
  87.         }  
  88.   
  89.         br.close();  
  90.   
  91.     }  
  92. }  
原创粉丝点击