All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.viiyue.plugins.mybatis.utils.IdGenerator Maven / Gradle / Ivy

Go to download

Mybatis generic mapper plugin for solving most basic operations, simplifying sql syntax and improving dynamic execution efficiency

There is a newer version: 1.3.7
Show newest version
/**
 * Copyright (C) 2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.viiyue.plugins.mybatis.utils;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 

Twitter Snowflake Id * *

* SnowFlake的结构如下(每部分用-分开):
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - * 000000000000
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序类的startTimestamp属性)。 * 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
* 10位的数据机器位,可以部署在1024个节点,包括5位dataCenterId和5位workerId
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
* 加起来刚好64位,为一个Long型。
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。 *

* * @author Twitter * @author tangxbai * @since 1.1.0 */ public class IdGenerator { private static IdGenerator generator = null; private static final String workerIdErrorMessage = "worker Id can't be greater than %d or less than 0"; private static final String dataCenterIdErrorMessage = "datacenter Id can't be greater than %d or less than 0"; private static final String clockBackwardErrorMessage = "Clock moved backwards. Refusing to generate id for %d milliseconds"; /** Worker Id [ 0-31 ] */ private long workerId; /** Data center Id [ 0-31 ] */ private long dataCenterId; /** Sync object for non-fair locks */ private final Lock lock = new ReentrantLock(); /** Start timestamp ( 2019-01-01 ) */ private final long startTimestamp = 1548950400000L; /** The number of bits in the machine Id */ private final int workerIdBits = 5; /** The number of digits in the data identifier Id */ private final int dataCenterIdBits = 5; /** The number of bits in the sequence in the Id */ private final int sequenceBits = 12; /** The maximum machine Id supported, the result is 31 */ private final int maxWorkerId = ~ ( -1 << workerIdBits ); /** The maximum supported data identifier Id, the result is 31 */ private final int maxDataCenterId = ~ ( -1 << dataCenterIdBits ); /** Generate a mask for the sequence, here 4095 ( 0b111111111111 = 0xfff = 4095 ) */ private final int maxSequenceMask = ~ ( -1 << sequenceBits ); /** Machine Id shifts 12 bits to the left */ private final long workerIdShift = sequenceBits; /** Data ID Id is shifted to the left by 17 digits ( 12 + 5 ) */ private final int dataCenterIdShift = sequenceBits + workerIdBits; /** Time is shifted to the left by 22 bits ( 5 + 5 + 12 ) */ private final int timestampShift = sequenceBits + workerIdBits + dataCenterIdBits; /** Sequence within milliseconds [ 0-4095 ] */ private volatile long sequence = 0L; /** The time when the last Id was generated */ private volatile long lastTimestamp = 0L; /** * Constructor initializes machine Id and data center Id * * @param workerId worker id [ 0-31 ] * @param dataCenterId data center id [ 0-31 ] */ private IdGenerator( int workerId, int dataCenterId ) { if ( workerId > maxWorkerId || workerId < 0 ) { throw new IllegalArgumentException( String.format( workerIdErrorMessage, maxWorkerId ) ); } if ( dataCenterId > maxDataCenterId || dataCenterId < 0 ) { throw new IllegalArgumentException( String.format( dataCenterIdErrorMessage, maxDataCenterId ) ); } this.workerId = workerId; this.dataCenterId = dataCenterId; } /** * Block until the next millisecond until a new timestamp is obtained * * @param lastTimestamp last generated timestamp * @return fixed timestamp */ private long blockNextMillis( long lastTimestamp ) { long current = timeGen(); while ( current <= lastTimestamp ) { current = timeGen(); } return current; } /** * Get the current system timestamp * * @return current system time millis */ private long timeGen() { return System.currentTimeMillis(); } /** * Get the next serialization Id * * @return next generated sequence id */ private long createId() { try { lock.lock(); long currentTimestamp = timeGen(); if ( currentTimestamp < lastTimestamp ) { throw new RuntimeException( String.format( clockBackwardErrorMessage, lastTimestamp - currentTimestamp ) ); } if ( lastTimestamp == currentTimestamp ) { sequence = ( sequence + 1 ) & maxSequenceMask; if ( sequence == 0 ) { currentTimestamp = blockNextMillis( lastTimestamp ); } } else { sequence = 0; } lastTimestamp = currentTimestamp; return ( ( currentTimestamp - startTimestamp ) << timestampShift ) | ( dataCenterId << dataCenterIdShift ) | ( workerId << workerIdShift ) | sequence; } finally { lock.unlock(); } } /** * Get the next long {@code Id} * * @return unique {@code Id} of the long type */ public static final long nextId() { return init().createId(); } /** * Get the next string {@code Id} * * @return unique {@code Id} of the string type */ public static final String nextIdString() { return String.valueOf( init().createId() ); } /** * Initialize the default generator, * data center id and worker id randomly generated. * * @return default Id generator */ public static final IdGenerator init() { if ( generator == null ) { Random random = new Random(); return init( random.nextInt( 31 ), random.nextInt( 31 ) ); } return generator; } /** * Initialize the custom generator, * you can specify the worker id and data center id. * * @param workerId worker id, the range is 0-31 * @param dataCenterId data center id, the range is 0-31 * @return custom generator */ public static final IdGenerator init( int workerId, int dataCenterId ) { if ( generator == null ) { synchronized ( IdGenerator.class ) { if ( generator == null ) { generator = new IdGenerator( workerId, dataCenterId ); } } } return generator; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy