24.Redis实现全局唯一ID
是一种分布式系统下用来生成全局唯一ID的工具。
特点
1.唯一性
2.高可用
3.高性能
4.递增性,数据也要保持一种递增,有利于数据库进行查询。
5.安全性
全局唯一ID的生成策略
1.UUID(没有顺序,字符串类型,效率不高)
2.Redis自增
3.snowflake算法
4.数据库自增(单独设计一张表存放多张表的主键id)
Redis自增ID策略
每天一个key,方便统计订单量。
ID构造是时间戳+计数器
package com.xkj.org.utils;
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;
@Component
public class RedisIdWorker {
/**
* 开始时间戳
*/
private static final long BEGIN_TIMESTAMP = 1640995200L;
/**
* 序列号的位数
*/
private static final int COUNT_BITS = 32;
private StringRedisTemplate stringRedisTemplate;
public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
public long nextId(String keyPrefix) {
// 1.生成时间戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
// 2.生成序列号
// 2.1.获取当前日期,精确到天
String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
// 2.2.自增长
long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
// 3.拼接并返回
// timestamp的值向左移动32位,然后加上count的值
return timestamp << COUNT_BITS | count;
}
}
package com.xkj.org;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xkj.org.entity.Shop;
import com.xkj.org.entity.Student;
import com.xkj.org.service.impl.ShopServiceImpl;
import com.xkj.org.utils.CacheClient;
import com.xkj.org.utils.RedisConstants;
import com.xkj.org.utils.RedisIdWorker;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@SpringBootTest
public class SpringBootDataRedisTest {
@Resource
private RedisIdWorker redisIdWorker;
private ExecutorService executorService = Executors.newFixedThreadPool(500);
@Test
void testIDWorker() throws InterruptedException {
long begin = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(300);
Runnable task = () -> {
for (int i = 0; i < 100; i++) {
long orderId = redisIdWorker.nextId("order");
System.out.println("orderId=="+orderId);
}
countDownLatch.countDown();
};
for (int i = 0; i < 300; i++) {
executorService.submit(task);
}
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("耗费时间:"+(end - begin));
}
}
因为是多个线程交叉运行,所以输出的结果没有顺序性。其实它是有序的。
产生的id也是long型的。
可以统计出这一天产生的订单数量。