扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
本篇内容主要讲解“数据库如何使用数据生成Sequence”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“数据库如何使用数据生成Sequence”吧!
创新互联公司一直通过网站建设和网站营销帮助企业获得更多客户资源。 以"深度挖掘,量身打造,注重实效"的一站式服务,以网站设计、成都做网站、移动互联产品、营销型网站服务为核心业务。10余年网站制作的经验,使用新网站建设技术,全新开发出的标准网站,不但价格便宜而且实用、灵活,特别适合中小公司网站制作。网站管理系统简单易用,维护方便,您可以完全操作网站资料,是中小公司快速网站建设的选择。
twitter 开源的分布式 id 生成算法,使用64 位的 long 型的 id。
41 bit,时间戳,单位为毫秒,2^41 - 1 换算成年可以表示69年的时间
10 bit,其中5个表示机房,5个表示机器ID
12 bit,录同一个毫秒内产生的不同 id,2^12 - 1 = 4096,可以表示同一个毫秒内的 4096 个不同的 id
支持每秒几万并发
public class UniqueOrderGenerate {// ==============================Fields===========================================/** 开始时间截 (2018-07-03) */private final long twepoch = 1530607760000L;/** 机器id所占的位数 */private final long workerIdBits = 5L;/** 数据标识id所占的位数 */private final long datacenterIdBits = 5L;/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */private final long maxWorkerId = -1L ^ (-1L << workerIdBits);/** 支持的最大数据标识id,结果是31 */private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);/** 序列在id中占的位数 */private final long sequenceBits = 12L;/** 机器ID向左移12位 */private final long workerIdShift = sequenceBits;/** 数据标识id向左移17位(12+5) */private final long datacenterIdShift = sequenceBits + workerIdBits;/** 时间截向左移22位(5+5+12) */private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */private final long sequenceMask = -1L ^ (-1L << sequenceBits);/** 工作机器ID(0~31) */private long workerId;/** 数据中心ID(0~31) */private long datacenterId;/** 毫秒内序列(0~4095) */private long sequence = 0L;/** 上次生成ID的时间截 */private long lastTimestamp = -1L;//==============================Constructors=====================================/** * 构造函数 * @param workerId 工作ID (0~31) * @param datacenterId 数据中心ID (0~31) */public UniqueOrderGenerate(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}this.workerId = workerId;this.datacenterId = datacenterId;}// ==============================Methods==========================================/** * 获得下一个ID (该方法是线程安全的) * @return SnowflakeId */public synchronized long nextId() {long timestamp = timeGen();//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}//如果是同一时间生成的,则进行毫秒内序列if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;//毫秒内序列溢出if (sequence == 0) {//阻塞到下一个毫秒,获得新的时间戳timestamp = tilNextMillis(lastTimestamp);}}//时间戳改变,毫秒内序列重置else {sequence = 0L;}//上次生成ID的时间截lastTimestamp = timestamp;//移位并通过或运算拼到一起组成64位的IDreturn (((timestamp - twepoch) << timestampLeftShift) //| (datacenterId << datacenterIdShift) //| (workerId << workerIdShift) //| sequence);}/** * 阻塞到下一个毫秒,直到获得新的时间戳 * @param lastTimestamp 上次生成ID的时间截 * @return 当前时间戳 */protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}/** * 返回以毫秒为单位的当前时间 * @return 当前时间(毫秒) */protected long timeGen() {return System.currentTimeMillis();}//==============================Test=============================================/** 测试 */public static void main(String[] args) {UniqueOrderGenerate idWorker = new UniqueOrderGenerate(0, 0);for (int i = 0; i < 1000; i++) {long id = idWorker.nextId();//System.out.println(Long.toBinaryString(id));System.out.println(id);}}}
在数据库中维护一张表
CREATE TABLE `sequence` ( `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `unique_id` bigint(18) DEFAULT NULL COMMENT 'unique_id', `UPDATED_TIME` timestamp NOT NULL COMMENT '更新时间', PRIMARY KEY (`ID`))
初始化:
设置步长step=5000, min = 0, max = 5000
截取时间字符串到当天,curTime = ‘20190520’
和步长拼接,uniqueId = curTime + step = 201905201000
主要思路:
每台应用服务器预先取步长,存在JVM内存中,nextKey++,步长用尽,更新数据库。
数据库建表,保存uniqueId,updateTime
设置数据库更新步长,每次到达步长更新数据库
根据业务量设置uniqueId长度,可以使用bigInt
时间加步长拼接作为唯一id
伪代码
取步长 getUniqueueId() {if nextKey > max || curTime == null operaDb() nextKey++ seq = curTime + step}操作数据库 operatDb() {查询db当前uniqueId 当前uniqueId + step}
到此,相信大家对“数据库如何使用数据生成Sequence”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流