速度很快,一万个才半秒
最安全,比随机数安全多了
长度合适,不想随机数很长
16位id,比如2019073000000041,前八位日期,后八位redis计数器,格式化成八位长数字字符串
策略:
每个表作为hash的key,日期作为hashKey,计数器作为hash值
每天日期变更,使用新的hashKey,
之所以不覆盖旧的日期key,为了容错。假设集群下不同机器的时间有误差,可能这个机器是今天,另外机器是昨天。
定时任务删除前天的key,昨天的保留,适当冗余。
@Component
public class RedisId {
private String DISTRIBUTE_ID = "DISTRIBUTE_ID:";
private String date = LocalDate.now().toString().replace("-", "");
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private RedisLockRegistry redisLockRegistry;
@Scheduled(cron = "0 0 0 0/1 * *")
public void init() {
deleteOldDays();
}
public void deleteOldDays() {
//置换当前日期
date = LocalDate.now().toString().replace("-", "");
//删除前天的id
Lock lock = redisLockRegistry.obtain("DELETE_OLD_DAYS");
try {
boolean b = lock.tryLock(1, TimeUnit.MINUTES);
if (!b) {
return;
}
Set<String> keys = redisTemplate.keys(DISTRIBUTE_ID + "*");
if (keys == null || keys.size() == 0) {
return;
}
String yesterday = LocalDate.now().minusDays(1).toString().replace("-", "");
keys.forEach(key -> {
Set<Object> daySet = redisTemplate.opsForHash().keys(key);
if (daySet != null && daySet.size() > 0) {
daySet.forEach(day -> {
if (day.toString().compareTo(yesterday) < 0) {
redisTemplate.opsForHash().delete(key, day);
}
});
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public String getId() {
return doGetId("COMMON");
}
public String getMachineId() {
return doGetId("MACHINE");
}
private String doGetId(String key) {
Long increment = redisTemplate.opsForHash().increment(DISTRIBUTE_ID + key, date, 1);
return date + String.format("%08d", increment);
}
}
每个表使用一个方法,提高并发性
使用举例
@RestController
@RequestMapping("/redisId")
public class RedisIdController {
@Autowired
private RedisId redisId;
@RequestMapping("/commonId")
public String commonId(){
return redisId.getId();
}
@RequestMapping("/machineId")
public String machineId(){
return redisId.getMachineId();
}
@RequestMapping("/deleteOldDays")
public String deleteOldDays(){
redisId.deleteOldDays();
return "deleteOldDays ok";
}
//一万个id才半秒,速度很快
@RequestMapping("/manyId")
public String manyId(){
LocalDateTime now = LocalDateTime.now();
for (int i = 0; i < 10000; i++) {
redisId.getId();
}
System.out.println(Duration.between(now, LocalDateTime.now()));//PT0.511S
return "manyId ok";
}
}