[size=medium][color=brown][b]全局主键生成器[/b][/color][/size]
[color=indigo][b]
介绍:
相对于DB自增序列的全局主键生成器,性能更高,同时保留业务需求的业务含义,
对于有分库分表需求的业务同时可以存储分库和分表的信息,对于高并发的互联网企业分库分表生成主键来说是一种很好的方法
[/b][/color]
[color=indigo][b]
介绍:
相对于DB自增序列的全局主键生成器,性能更高,同时保留业务需求的业务含义,
对于有分库分表需求的业务同时可以存储分库和分表的信息,对于高并发的互联网企业分库分表生成主键来说是一种很好的方法
[/b][/color]
package com.tongbanjie.trade.test.base;
import java.net.InetAddress;
import org.apache.commons.lang.StringUtils;
import com.tongbanjie.commons.util.TSS;
public class TestGenId {
public static void main(String[] args) throws Exception {
/**
* 项目:交易单分表
*
* 需求
* 查询需求: 1. userId维度
* 2. 产品维度
* 3. 商户维度
* 4. 时间区间维度
*
* 预计订单量:
* 一单平均10000, 一年交易额5000亿, 需要成功订单量 = 500000000000 / 10000 = 50000000 5000万订单
* 购买加回款应该是1亿订单量, 所以, 单表2000万, 一年需要5张表
*
* 最后扩展64库 + 64表, 共64*64 = 4096表, 4096 * 2000万 = 819亿订单够用了, 819亿 * 10000 = 8190000亿 819万亿,够用了
*
* 全局唯一主键:
* 15位时间戳 + 自增序号四位 + 机器后两段IP,6位 + 备用1位 + 分库信息两位 + 分表信息两位 共30位, 回款改造前
* 15位时间戳 + 自增序号四位 + 机器后两段IP,6位 + 备用3位 + 分库信息两位 + 分表信息两位 共32位, 回款改造后
*
* 单JVM支持最多1s 1000 * 9999 = 9999000, 999万9千笔订单,后续还可以扩展。
*
* 分库规则:
* 寻找到数据库 (userId/100) % 64 + 1 找到数据库 订单最多64个库 目前一个库 二分法裂变扩容
* 分表规则:
* 寻找到表信息 userId % 64 + 1 找到表信息 一个库最多64个表 目前分8张表 以后二分法裂变扩容
*
* 迁移规则:
* 迁移方案同步写, 目前用动态表名, 以后分表中间件稳定后, 迁移过去
*
* 查询改造:
* 原接口不变,对用户无感知, 底层钩子遍历
*/
// 只获取本地局域网IP即可
String ip = InetAddress.getLocalHost().getHostAddress();
String[] ipArray = ip.split("\\.");
final String lastTwoPhaseIp = StringUtils.rightPad(ipArray[2], 3, '0')
+ StringUtils.leftPad(ipArray[3], 3, '0');
for (int i = 0; i < 100000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TSS commons工具类
String tss = TSS.getTimeStampSequence();
String id = tss + lastTwoPhaseIp + "000" + "01" + "08";
System.out.println(id);
}
}).start();
}
}
}
package com.tongbanjie.commons.util;
import org.apache.commons.lang.StringUtils;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
* 时间戳序列器<br>
*
* 支持同一毫秒最多生成9999笔序列号<br>
* @author sanfeng
*
* 想象力就是生产力
*/
public class TSS {
// 默认1个大小
private static HashMap<String, AtomicInteger> tssCache
= new HashMap<String, AtomicInteger>(1);
private static final ReentrantLock lock = new ReentrantLock();
// 因为有锁,所以是变成了线程安全的,省去每次 new 的消耗,耗时降低约一半
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmssSSS");
public static String getTimeStampSequence() {
String timestamp = null;
String inc = null;
lock.lock();
try {
timestamp = sdf.format(new Date());
AtomicInteger value = tssCache.get(timestamp);
if(value == null) {
tssCache.clear();
int defaultStartValue = 0;
tssCache.put(timestamp, new AtomicInteger(defaultStartValue));
inc = String.valueOf(defaultStartValue);
} else {
inc = String.valueOf(value.addAndGet(1));
}
} finally {
lock.unlock();
}
return timestamp + StringUtils.leftPad(inc, 4, '0');
}
public static void main(String[] args) throws Exception {
// for (int i = 0; i < 1000; i++) {
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// for (int j = 0; j < 10; j++) {
// System.out.println(TSS.getTimeStampSequence());
// }
// }
// }).start();
// }
// 统计重复
HashSet<String> set = new HashSet<String>();
BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream("C:/Users/Administrator/Desktop/1.txt")));
String str = br.readLine();
while(str != null) {
if(set.contains(str)) {
System.out.println(str);
} else {
set.add(str);
}
str = br.readLine();
}
br.close();
}
}