プロジェクトがグローバル一意のidプライマリ・キーを生成する方法
7600 ワード
一.新規自己増分リスト方式
mysqlを使用して、idだけが自動的に増加するテーブルを新規作成し、idを取得するたびに、まず自己増順リストにデータを書き込み、idを取得します.
欠点:
1.ライブラリシーンには適用されません
2.特高同時シーンには適用されません
メリット:
1.mysqlデータベース自体によるシンプル化
二.新規シーケンス方式
Oracle、SQLserverに適用
メリット:
1.適用ライブラリ表
三.UUID方式
UUIDにより生成
メリット:
1.第三者に依存しない
欠点:
1.不連続
四.スノーアルゴリズム
メリット:
1.第三者に依存しない
2.実現が簡単
3.適用ライブラリ表
mysqlを使用して、idだけが自動的に増加するテーブルを新規作成し、idを取得するたびに、まず自己増順リストにデータを書き込み、idを取得します.
CREATE TABLE `org_dept` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`) USING BTREE
);
欠点:
1.ライブラリシーンには適用されません
2.特高同時シーンには適用されません
メリット:
1.mysqlデータベース自体によるシンプル化
二.新規シーケンス方式
Oracle、SQLserverに適用
-- 1 :
create sequence seq_id increment 1 start 1000000000000 ;
-- 2 :
create sequence seq_id increment 1 start 2000000000000 ;
--
create table t_table_name(
n_id bigint not null default nextval('seq_id'), --
--
primary key(n_id)
);
メリット:
1.適用ライブラリ表
三.UUID方式
UUIDにより生成
メリット:
1.第三者に依存しない
欠点:
1.不連続
四.スノーアルゴリズム
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.ToString;
/**
* Copyright: Copyright (c) 2019
*
* @ClassName: IdWorker.java
* @Description: SnowFlake , Twitter id 。
* : 64 bit long id。
* 64 bit , 1 bit , 41 bit ,
* 10 bit id,12 bit
*
* @version: v1.0.0
* @author: BianPeng
* @date: 2019 4 11 3:13:41
*
* Modification History:
* Date Author Version Description
*---------------------------------------------------------------*
* 2019 4 11 BianPeng v1.0.0 initialize
*/
@ToString
public class SnowflakeIdFactory {
static Logger log = LoggerFactory.getLogger(SnowflakeIdFactory.class);
private final long twepoch = 1288834974657L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long sequenceBits = 12L;
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeIdFactory(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;
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
// ,ID .
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;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected long timeGen() {
return System.currentTimeMillis();
}
public static void testProductIdByMoreThread(int dataCenterId, int workerId, int n) throws InterruptedException {
List tlist = new ArrayList<>();
Set setAll = new HashSet<>();
CountDownLatch cdLatch = new CountDownLatch(10);
long start = System.currentTimeMillis();
int threadNo = dataCenterId;
Map idFactories = new HashMap<>();
for(int i=0;i<10;i++){
// map key.
idFactories.put("snowflake"+i,new SnowflakeIdFactory(workerId, threadNo++));
}
for(int i=0;i<10;i++){
Thread temp =new Thread(new Runnable() {
@Override
public void run() {
Set setId = new HashSet<>();
SnowflakeIdFactory idWorker = idFactories.get(Thread.currentThread().getName());
for(int j=0;j setOne = new HashSet<>();
Set setTow = new HashSet<>();
long start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
setOne.add(idWorker.nextId());// set
}
long end1 = System.currentTimeMillis() - start;
log.info(" ID {} , {} <<<>>> :{}",n,setOne.size(),end1);
for (int i = 0; i < n; i++) {
setTow.add(idWorker2.nextId());// set
}
long end2 = System.currentTimeMillis() - start;
log.info(" ID {} , {} <<<>>> :{}",n,setTow.size(),end2);
setOne.addAll(setTow);
log.info(" ID :{}",setOne.size());
}
public static void testPerSecondProductIdNums(){
SnowflakeIdFactory idWorker = new SnowflakeIdFactory(1, 2);
long start = System.currentTimeMillis();
int count = 0;
for (int i = 0; System.currentTimeMillis()-start<1000; i++,count=i) {
/** : ID, ID 400w+ */
//idWorker.nextId();
/** : log , ID, ID log.error() .
* 10 . */
log.info(""+idWorker.nextId());
}
long end = System.currentTimeMillis()-start;
System.out.println(end);
System.out.println(count);
}
public static void main(String[] args) {
/** case1: id ?
* : id 400w+
*/
//testPerSecondProductIdNums();
/** case2: - N id, id ?
* : , .
*/
//testProductId(1,2,10000);// !
//testProductId(1,2,20000);// !
/** case3: - N id, id ?
* : , .
*/
try {
testProductIdByMoreThread(1,2,100000);// , !
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
メリット:
1.第三者に依存しない
2.実現が簡単
3.適用ライブラリ表