唯一流水号生成方式汇总实现类--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 <br>
     *         1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
     *         41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
     *             得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
     *         10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
     *         12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
     *             加起来刚好64位,为一个Long型。<br>
     *         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());
    }

 

上一篇:狂神说Java】Redis详解


下一篇:StringUtils.join()方法的方法和使用