ID生成策略——基于redis生成全局唯一ID,单体、集群、分布式均适用

网上很多全局唯一ID的生成策略,感兴趣的可以去百度看看,自己写的一个基于reids生成id的一个ID要求就是:唯一性、安全性=》高可用、高性能、递增性

一、分析

  1. 特性:
    在这里插入图片描述
    2.规则
    在这里插入图片描述
  2. 总结:
    在这里插入图片描述

二、代码

package com.hmdp.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * 基于redis全局唯一ID生成器
 *  优点:1.唯一(不必说了)
 *       2.单调递增(天然排序、分页优势)
 *       4.不依赖与关系型数据库,灵活方便。
 *       3.sql索引的查询效率,long类型的值比String的查询效率高。
 * @author TH
 * @date 2022/3/24
 */
@Component
public class RedisIdGenerator {

    /**
     * 自定义的一个开始时间戳2022-01-05 00:00:00
     */
    private final static long BEGIN_TIMESTAMP=1641340800L;
    /**
     * 步长/变化数量:一般情况集群有多台redis那么有几台步长就设置多少
     */
    private final static long DELTA=1L;
    /**
     *序列号的一个位数。
     */
    private final static  int COUNT_BITS=32;
    /**
     * 时间格式
     */
    private final static String PATTERN="yyyy:MM:dd";


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取下一个ID值
     * @param keyPrefix
     * @return
     */
    public long nextId(String keyPrefix){
        //1.高位值,获取当前系统时间与指定时间的时间戳差值
        LocalDateTime now = LocalDateTime.now();
        long nowTime = now.toEpochSecond(ZoneOffset.UTC);
        long nowTimeStamp = nowTime - BEGIN_TIMESTAMP;
        //2.低位值
        //2.1获取key的时间规则
        String sTime = now.format(DateTimeFormatter.ofPattern(PATTERN));
        //2.2 获取redis的单点自增值,如果key不存在,那么会新增一个key作为起始值。1个redis的时候方式一
        //long endTimesTamp = stringRedisTemplate.opsForValue().increment("idIncr:" + keyPrefix + ":" + sTime);
        //2.2 如果是集群下有多台redis那么有几台步长就设置多少。
        long endTimesTamp = stringRedisTemplate.opsForValue().increment("idIncr:" + keyPrefix + ":" + sTime,DELTA);
        //3.拼接返回,数值的一种拼接方式,把时间戳移动到高位,位运算、或运算。
        return nowTimeStamp << COUNT_BITS | endTimesTamp;
    }

    public static void main(String[] args) {
        //设置指定日期2222-01-05 00:00:00
        LocalDateTime dateTime = LocalDateTime.of(2022, 1, 5, 0, 0, 0);
        //获取秒的时间戳,UTC-现世界标准时间
        long second = dateTime.toEpochSecond(ZoneOffset.UTC);
        System.out.println("second="+second);
    }
}

2.测试代码:

private ExecutorService es= Executors.newFixedThreadPool(10);
    /**
     * 测试id生成器:模拟20000个ID并发生成
     */
    @Test
    void testIdGenerator() throws InterruptedException {
        CountDownLatch downLatch=new CountDownLatch(200);
        Runnable task=()->{
            for (int i = 0; i < 100; i++) {
                long orderId = redisIdGenerator.nextId("orderId");
                System.out.println("id="+orderId);
            }
            downLatch.countDown();
        };
        long begin=System.currentTimeMillis();
        for (int i = 0; i < 200; i++) {
            es.submit(task);
        }
        downLatch.await();
        long end=System.currentTimeMillis();
        //花费时常会比实际生成id的时间稍微长一点点。毕竟多了一些打印啊什么的。
        System.out.println("time="+(end-begin));
    }
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值