自增id:存储空间小,性能高,但在分布式系统,以及多数据库数据交换,会出现问题。

uuid:优点就是保证唯一,本身具有无序性,正式系统推荐使用uuid。

但是因为UUID是无序性的,本身的size过大,作为主键会涉及大量索引重排。

名称有序分布式
自增是否
uuid否是

因为分布式的优先级大于是否有序,所以数据库不能使用自增主键。

这时候需要一份分布式且有序的主键生成算法:雪花算法。

/**
 * @author qushen
 * @create 2022/5/29 10:51
 */
public class SnowFlake {

    /**
     * 组成部分
     */

    //最高符号为0

    //时间戳
    private final long  fixedTimeStamp=1234567L;
    //机房id
    private  long computerRoomId;

    //机器id
    private  long machineId;

    //序列号 默认初始值为0
    private  long sequence =0L;


    /**
     * 设置每个组所占用的bit
     */
    //最高符 占用1bit

    //时间戳 占用41bit
            
    //机房id 占用5bit
    private final long computerRoomBitCnt=5L;

    //机器id 占用5bit
    private final long machineBitCnt=5L;

    //序列号 占用12bit
    private final long sequenceBitCnt=12L;


    /**
     * 设置每个组 位移的位数
     */

    //机器id  左移12位(序列号所占的位数)
    private final  long machineIdShift=sequenceBitCnt;

    //机房id  左移12+5位(序列号+机器id所占的位数)
    private final  long computerRoomIdShift=sequenceBitCnt+machineIdShift;

    //时间戳  左移12+5+5位(序列号+机器id+机房id所占的位数)
    private final long timeStampShift=computerRoomIdShift+computerRoomBitCnt;

    /**
     * 聚合信息
     */
    //支持的最大 机房id为31位=2^5-1
    private final long maxComputerRoomId=-1 ^(-1 << computerRoomBitCnt);

    //支持的最大 机器id为31位=2^5-1
    private final long maxMachineId=-1 ^(-1 << machineBitCnt);

    //序列号掩码
    private final long sequenceMask=-1 ^(-1 << sequenceBitCnt);

    //上一次生成的时间戳
    private  long lastTimeStamp=-1L;


    public SnowFlake(long computerRoomId,long machineId){

        if(computerRoomId<0 || computerRoomId>maxComputerRoomId){
            throw new IllegalArgumentException("computerRoomId out of range");
        }

        if(machineId<0 || machineId>maxMachineId){
            throw new IllegalArgumentException("machineId out of range");
        }

      this.computerRoomId=computerRoomId;
      this.machineId=machineId;


    }

    /**
     * 返回毫秒级的时间戳
     * @return
     */
    protected  long getCurrentTime(){

        return System.currentTimeMillis();
    }

    protected  synchronized  long getNexId(){

        //拿到时间戳
       long currentTimeStamp  =getCurrentTime();


       if (currentTimeStamp==lastTimeStamp){
           sequence = (sequence+1) & sequenceMask;  //取模
           //代表该毫秒级所能生成的唯一id已经使用完了
           if(sequence == 0){
               currentTimeStamp = getNexMillis();
           }

       }else {
           sequence = 0;
       }

       lastTimeStamp =currentTimeStamp;

       //唯一Id
       return (currentTimeStamp - fixedTimeStamp<< timeStampShift) |
               (computerRoomId << computerRoomIdShift) |
               (maxMachineId << machineIdShift) |
               sequence ;

    }

    protected long getNexMillis(){

        long currentTimeStamp=getCurrentTime();
        while(currentTimeStamp<=lastTimeStamp){
            currentTimeStamp =getCurrentTime();
        }
        return  currentTimeStamp;

    }

    public static void main(String[] args) {
        SnowFlake snowFlake = new SnowFlake(0, 0);
        System.out.println(snowFlake.getNexId());
    }
}

更多推荐