自学内容网 自学内容网

使用Redis生成全局唯一id

为了生成一个符合要求的分布式全局ID,我们可以使用 StringRedisTemplate 来实现。这个ID由三部分组成:

  1. 符号位(1 bit):始终为0,表示正数。
  2. 时间戳(31 bit):表示从某个起始时间点(例如2023-01-01 00:00:00)到现在的秒数。
  3. 序列号(32 bit):用于在同一秒内生成不同的ID。

实现步骤

  1. 计算时间戳:从某个起始时间点到现在的秒数。
  2. 生成序列号:使用Redis的原子递增操作来生成序列号。
  3. 组合ID:将时间戳和序列号组合成一个64位的长整型数字。

代码实现

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

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;

@Service
public class DistributedIdGenerator {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // 起始时间点,例如2023-01-01 00:00:00
    private static final long EPOCH = ZonedDateTime.of(2023, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()).toInstant().toEpochMilli() / 1000;

    // 序列号的Redis键前缀
    private static final String SEQUENCE_KEY_PREFIX = "sequence:";

    /**
     * 生成分布式全局ID
     *
     * @return 分布式全局ID
     */
    public long generateId() {
        // 获取当前时间戳(从起始时间点到现在的秒数)
        long currentTimeSec = Instant.now().getEpochSecond() - EPOCH;

        // 生成序列号
        String sequenceKey = SEQUENCE_KEY_PREFIX + currentTimeSec;
        long sequence = stringRedisTemplate.opsForValue().increment(sequenceKey, 1);
        if (sequence >= (1L << 32)) { // 序列号溢出,重置为0
            stringRedisTemplate.expire(sequenceKey, 1, TimeUnit.SECONDS); // 设置1秒后过期
            sequence = 0;
        }

        // 组合ID
        long id = (currentTimeSec << 32) | sequence;

        return id;
    }
}

代码解释

  1. EPOCH:起始时间点,例如2023-01-01 00:00:00,转换为秒数。
  2. SEQUENCE_KEY_PREFIX:Redis中存储序列号的键前缀。
  3. generateId 方法
    • currentTimeSec:从起始时间点到现在的秒数。
    • sequenceKey:根据当前时间戳生成的Redis键。
    • sequence:使用 opsForValue().increment 方法生成序列号,确保在同一秒内生成不同的ID。
    • 序列号溢出处理:如果序列号达到最大值(2^32 - 1),则重置为0,并设置键在1秒后过期。
    • 组合ID:将时间戳左移32位,然后与序列号进行按位或操作,生成最终的64位ID。

测试代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IdController {

    @Autowired
    private DistributedIdGenerator idGenerator;

    @GetMapping("/generate-id")
    public long generateId() {
        return idGenerator.generateId();
    }
}


原文地址:https://blog.csdn.net/2302_79741013/article/details/143996477

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!