全局主键生成器-支持单JVM1秒近1000万订单生成

[size=medium][color=brown][b]全局主键生成器[/b][/color][/size]
[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();

}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值