唯一流水号生成方式汇总实现类--SerialImpl
======================================================唯一流水号生成接口类:
/** * 序列号接口引擎 */ public interface Serial { /** * 根据序列号代码,创建不同的序列号 * @param serialCode * @return */ public String modLSerial(String serialCode); /** * 根据序列号代码,创建不同的序列号 * @param serialCode * @return */ public String globalLockSerial1(); public String globalLockSerial2(); /** * UUID实现序列获取(36位),字母小写 * @return */ public String uuidSerial(); /** * UUID实现序列获取(32位),字母小写 * @return */ public String uuid2Serial(); /** * UUID实现序列获取(32位),字母大写 * @return */ public String uuid3Serial(); /** * 雪花算法实现自增序列(Long类型字符串 18位) * @return reg 928 40863 21926 63585 */ public String snowLongSerial(); public String snowLongSerial(int strLen); /** * 雪花算法实现自增序列(二进制字符串,60位) * @return */ public String snowBinarySerial(); }
======================================================唯一流水号生成接口实现类:
import org.apache.commons.lang3.StringUtils; import com.taoxw.utils.string.StringFormatUtil; public class SerialImpl implements Serial { /** * 实现全局唯一ID,有三种方式,分别是通过中间件方式、UUID、雪花算法 * * 中间件方式: 把数据库或者redis缓存作为媒介,从中间件获取ID * 优点: 全局的递增趋势 * 缺点: 1.依赖中间件,假如中间件挂了,就不能提供服务了;2.依赖中间件的写入和事务,会影响效率;3.若数据量大,你还得考虑部署集群,考虑走代理,问题复杂化 * 举例:1.通过数据库自增序列实现,需要设置不同的增长步长 * 2.基于redis生成全局id策略,因为Redis是单线的天生保证原子性,可以使用原子性操作INCR和INCRBY来实现,注意在Redis集群情况下,同MySQL一样需要设置不同的增长步长, * 同时key一定要设置有效期,可以使用Redis集群来获取更高的吞吐量 * * UUID: 通过UUID的方式,java.util.UUID就提供了获取UUID的方法,使用UUID来实现全局唯一ID * 优点: 操作简单,也能实现全局唯一的效果 * 缺点: 1.不能体现全局视野的递增趋势;2.太长了,UUID是32位,有点浪费;3.UUID是无序的,会造成中间节点的分裂,也会造成不饱和的节点,插入的效率自然就比较低下了 * * 雪花算法: 生成id的结果是一个64bit大小的整数 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。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左右。 */ @Override public String modLSerial(String serialCode) { if(StringUtils.isNotBlank(serialCode) && StringUtils.equals("mode1", serialCode)) { return SerialUtil.serialMode1(); } if(StringUtils.isNotBlank(serialCode) && StringUtils.equals("mode2", serialCode)) { return SerialUtil.serialMode2(); } if(StringUtils.isNotBlank(serialCode) && StringUtils.equals("mode3", serialCode)) { return SerialUtil.serialMode3(); } if(StringUtils.isNotBlank(serialCode) && StringUtils.equals("mode4", serialCode)) { return SerialUtil.serialMode4(); } if(StringUtils.isNotBlank(serialCode) && StringUtils.equals("mode5", serialCode)) { return SerialUtil.serialMode5(); } if(StringUtils.isNotBlank(serialCode) && StringUtils.equals("mode6", serialCode)) { return SerialUtil.serialMode6(); } return ""; } @Override public String globalLockSerial1() { return GlobalLockWorker.getSerialNumber1(); } @Override public String globalLockSerial2() { return GlobalLockWorker.getSerialNumber1(); } /** * 雪花算法-创建流水号 * 备注:从2015-01-01开始,创建一个long,位数18 */ @Override public String snowLongSerial() { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); long id = idWorker.nextId(); return Long.toString(id); } /** * 雪花算法-创建流水号, 指定位数 * 备注:1.从2015-01-01开始,创建一个long,位数18,补齐位数 * 2.strLen >= 18 */ @Override public String snowLongSerial(int strLen) { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); String id = Long.toString(idWorker.nextId()); return StringFormatUtil.leftPadForZero(id, strLen); } @Override public String snowBinarySerial() { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); long id = idWorker.nextId(); return Long.toBinaryString(id); } @Override public String uuidSerial() { return UuidWorker.toUuid(); } @Override public String uuid2Serial() { return UuidWorker.toUuid2(); } @Override public String uuid3Serial() { return UuidWorker.toUuid3(); } }
======================================================唯一流水号生成接口测试类:
@Test public void test_modLSerial() { Serial serialUtil = new SerialImpl(); System.out.println(serialUtil.modLSerial("mode1")); System.out.println(serialUtil.modLSerial("mode2")); System.out.println(serialUtil.modLSerial("mode3")); System.out.println(serialUtil.modLSerial("mode4")); System.out.println(serialUtil.modLSerial("mode5")); System.out.println(serialUtil.modLSerial("mode6")); } /** * UUID实现序列号获取 */ @Test public void test_uuidToSerial() { Serial serialUtil = new SerialImpl(); System.out.println(serialUtil.uuidSerial()); System.out.println(serialUtil.uuid2Serial()); System.out.println(serialUtil.uuid3Serial()); } /** * 雪花算法实现序列号自增 */ @Test public void test_snowflakeToSerial() { Serial serialUtil = new SerialImpl(); System.out.println(serialUtil.snowLongSerial()); System.out.println(serialUtil.snowLongSerial(19)); System.out.println(serialUtil.snowBinarySerial()); }