MySQL是一個(gè)開源的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),廣泛應(yīng)用于互聯(lián)網(wǎng)開發(fā)中。MySQL的id自增功能是我們經(jīng)常用到的一個(gè)功能,可以幫助我們自動(dòng)生成唯一的ID。
MySQL中的id自增功能通常會(huì)用到AUTO_INCREMENT關(guān)鍵字,我們可以在創(chuàng)建表的時(shí)候設(shè)置id字段為自增長(zhǎng)屬性。代碼如下:
CREATE TABLE table_name ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(30) NOT NULL, PRIMARY KEY (id) );
在使用該表插入數(shù)據(jù)時(shí),如果不指定id值,系統(tǒng)會(huì)自動(dòng)分配該字段的下一個(gè)可用的值。可以使用LAST_INSERT_ID()函數(shù)獲取到剛剛插入記錄的id值。
而雪花算法是Twitter提出的一種分布式id生成算法,可以生成唯一、有序、不連續(xù)的id。雪花算法的核心思想是將一個(gè)64位的二進(jìn)制數(shù)分成不同的部分,每個(gè)部分代表不同的意義,再進(jìn)行處理生成id號(hào)。雪花算法生成的ID具有一定的時(shí)間序列特性,因此在分布式場(chǎng)景下可以保證高效的ID生成和數(shù)據(jù)分片。
雪花算法的生成方式可以使用Java語言實(shí)現(xiàn),其核心代碼如下:
public class SnowflakeIdWorker { private static final long START_TIME_MILLIS = 1543229402000L; // 最初時(shí)間戳 private static final long SEQUENCE_BITS = 12L; // 序列號(hào)的位數(shù) private static final long WORKER_ID_BITS = 5L; // 機(jī)器id的位數(shù) private static final long MAX_SEQUENCE_NUM = ~(-1L<< SEQUENCE_BITS); // 序列號(hào)最大值 private static final long MAX_WORKER_NUM = ~(-1L<< WORKER_ID_BITS); // 機(jī)器id最大值 private static long lastTimeStamp = -1L; // 上次生成ID的時(shí)間戳 private static long sequenceNum = 0L; // 當(dāng)前序列號(hào) private final long workerId; // 機(jī)器id public SnowflakeIdWorker(long workerId) { if (workerId >MAX_WORKER_NUM || workerId< 0) { throw new IllegalArgumentException("workerId can't be greater than MAX_WORKER_NUM or less than 0!"); } this.workerId = workerId; } public synchronized long nextId() { long currentTimeMillis = System.currentTimeMillis(); // 獲取當(dāng)前時(shí)間戳 if (currentTimeMillis< lastTimeStamp) { throw new RuntimeException("Clock moved backwards, Refusing to generate id!"); } if (currentTimeMillis == lastTimeStamp) { // 同一毫秒內(nèi)生成多個(gè)id號(hào) sequenceNum = (sequenceNum + 1) & MAX_SEQUENCE_NUM; if (sequenceNum == 0) { // 當(dāng)前毫秒內(nèi)序列號(hào)已經(jīng)到達(dá)最大值 currentTimeMillis = getNextMillis(); } } else { // 不同毫秒內(nèi)生成id號(hào) lastTimeStamp = currentTimeMillis; sequenceNum = 0L; } return ((currentTimeMillis - START_TIME_MILLIS)<< (SEQUENCE_BITS + WORKER_ID_BITS)) | (workerId<< SEQUENCE_BITS) | sequenceNum; } private long getNextMillis() { long currentTimeMillis = System.currentTimeMillis(); while (currentTimeMillis<= lastTimeStamp) { currentTimeMillis = System.currentTimeMillis(); } return currentTimeMillis; } }
在使用雪花算法生成id時(shí),我們需要在不同的機(jī)器上運(yùn)行不同的服務(wù)實(shí)例,每個(gè)服務(wù)實(shí)例有不同的ID號(hào)。
兩種id生成方式各有優(yōu)缺點(diǎn),在實(shí)際開發(fā)中應(yīng)根據(jù)需要靈活應(yīng)用,選擇合適的方式進(jìn)行數(shù)據(jù)存儲(chǔ)和操作。