相信大家在分布式系统一定会遇到如何生成唯一Id;
uuid 可以但是,作为数据库主键很浪费性能(索引相关),
雪花算法可以, 但是很依赖于环境.
这里推荐大家使用redis生成;
1. 需求明确
我们生成的Id组成为, 时间戳+ 自增Id, 补0
例如: 今天是2020.2.28 , 补6个0 , 那么生成的id范围是20200228000001-202002289999999
2.技术选型
Redis中的RedisAtomicLong 具备原子性, 可以通过其incr方法进行递增.
2. ID生成类
package com.dyhospital.cloudhis.common.redis.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Description: 分布式Id生成工厂
* User: zhouzhou
* Date: 2020-02-28
* Time: 10:14
*/
@Component
public class IdGeneratorFactory {
@Autowired
RedisTemplate<String, String> redisTemplate;
/**
* @param key
* @param value
* @param expireTime
* @Title: set
* @Description: set cache.
*/
public void set(String key, int value, Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.set(value);
counter.expireAt(expireTime);
}
/**
* @param key
* @param value
* @param timeout
* @param unit
* @Title: set
* @Description: set cache.
*/
public void set(String key, int value, long timeout, TimeUnit unit) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.set(value);
counter.expire(timeout, unit);
}
/**
* @param key
* @return
* @Title: generate
* @Description: Atomically increments by one the current value.
*/
public long generate(String key) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
return counter.incrementAndGet();
}
/**
* @param key
* @return
* @Title: generate
* @Description: Atomically increments by one the current value.
*/
public long generate(String key, Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.expireAt(expireTime);
return counter.incrementAndGet();
}
/**
* @param key
* @param increment
* @return
* @Title: generate
* @Description: Atomically adds the given value to the current value.
*/
public long generate(String key, int increment) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
return counter.addAndGet(increment);
}
/**
* @param key
* @param increment
* @param expireTime
* @return
* @Title: generate
* @Description: Atomically adds the given value to the current value.
*/
public long generate(String key, int increment, Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.expireAt(expireTime);
return counter.addAndGet(increment);
}
/**
* 根据业务key, 长度, 获取key, 以日期作为前缀
* <p>
* key = order, length = 5 ,当天日期2050年1月1日
* 结果: 2050010100001
* </p>
* @param key
* @param length
* @return
*/
public String generateIdByToday(String key, Integer length) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
long num = counter.incrementAndGet();
counter.expireAt(getTodayEndTime());
String id = getToday() + String.format("%0" + length + "d", num);
return id;
}
/**
* @Title: getTodayEndTime 获取今日最后的时间
* @Description: Get the cache expire time.
* @return
*/
public static Date getTodayEndTime() {
Calendar todayEnd = Calendar.getInstance();
todayEnd.set(Calendar.HOUR_OF_DAY, 23);
todayEnd.set(Calendar.MINUTE, 59);
todayEnd.set(Calendar.SECOND, 59);
todayEnd.set(Calendar.MILLISECOND, 999);
return todayEnd.getTime();
}
/**
* @Title: getTodayEndTime 今天的日期格式: 20190101
* @Description: Get the cache expire time.
* @return
*/
public static String getToday() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(new Date());
}
}
3. 我们来测试下
测试类如下:
// --------------------- 分布式自增Id 测试 ---------------------------
@ApiOperation("根据key生成自增Id")
@RequestMapping(value = "/getId/{key}", method = RequestMethod.GET)
public GenericResponse<Long> getId(@PathVariable("key") String key) {
logger.info("生成Id中");
long generate = idGeneratorFactory.generate(key, IdGeneratorFactory.getTodayEndTime());
return new GenericResponse<>(generate);
}
@ApiOperation("根据key生成自增Id,日期版")
@RequestMapping(value = "/getIdByToday/{key}", method = RequestMethod.GET)
public GenericResponse<String> getIdByToday(@PathVariable("key") String key) {
logger.info("生成Id中");
String id = idGeneratorFactory.generateIdByToday(key, 6);
return new GenericResponse<>(id);
}
测试结果如下: