项目开发时,使用了两套数据库,开发环境和上线环境,数据库表中大多採用了自增主键,
比方:
id int unsigned primary key auto_increment,
但往往会碰到一些问题。比方:
开发环境中,使用爬虫抓取一些数据,建立索引。再把数据迁移到上线环境,会导致索引中的id和
上线环境数据库中id对不上,所以决定使用字符串作为主键。
那么问题来了,怎样生成唯一的序列号?
格式依照:yyyyMMdd+两位业务码+10位的自增序列。
比方20150101**99**0000000001。
思路:
获得日期非常easy;
业务码是调用服务传入的參数;
使用Redis来实现10位的自增序列的保存和自增,使用serial.number:{日期}的格式来保存某一天的自增序列的值;
主要代码例如以下:
public interface SerialNumberService {
/**
* 序列号自增序列
*/
String SERIAL_NUMBER = "serial.number:";
/**
* 依据两位业务码字符串,生成一个流水号,格式依照:<br/>
* yyyyMMdd{bizCode}{10位的自增序列号}
*
* @param bizCode
* 两位,00-99
* @return 20位的序列号
* @throws ServiceException
*/
String generate(String bizCode) throws ServiceException;
//事实上,应该对bizCode做白名单验证,以免恶意伪造
default boolean isLegal(String bizCode) {
if (bizCode == null || bizCode.length() != 2) {
throw new RuntimeException("bizCode: " + bizCode + "异常");
}
if (Character.isDigit(bizCode.charAt(0))
&& Character.isDigit(bizCode.charAt(1)))
return true;
return false;
}
}
@Service
public class SerialNumberServiceImpl implements SerialNumberService {
@Resource
private RedisDao redisDao;
@Override
public String generate(String bizCode) throws ServiceException {
/** 检查业务码 */
boolean isLegal = isLegal(bizCode);
if (!isLegal) {
throw new ServiceException("bizCode參数不合法");
}
/** 获取今天的日期:yyyyMMdd */
String date = TimeUtil.getToday();
/** 构造redis的key */
String key = SERIAL_NUMBER + date;
/** 自增 */
long sequence = redisDao.incr(key);
String seq = StringUtil.getSequence(sequence);
StringBuilder sb = new StringBuilder();
sb.append(date).append(bizCode).append(seq);
String serial = sb.toString();
return serial;
}
}
public class TimeUtil {
private TimeUtil() {
}
/**
* 获取今日日期
*
* @return
*/
public static String getToday() {
return "20150101";
}
}
public class StringUtil {
private StringUtil() {
}
static final int DEFAULT_LENGTH = 10;
/**
* 得到10位的序列号,长度不足10位,前面补0
*
* @param seq
* @return
*/
public static String getSequence(long seq) {
String str = String.valueOf(seq);
int len = str.length();
if (len >= DEFAULT_LENGTH) {// 取决于业务规模,应该不会到达10
return str;
}
int rest = DEFAULT_LENGTH - len;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rest; i++) {
sb.append('0');
}
sb.append(str);
return sb.toString();
}
}
仅仅声明了RedisDao接口,能够使用Jedisclient来实现。
public interface RedisDao {
String get(String key);
/**
* 自增,+1,返回添加后的值
*
* @param key
* @return
*/
long incr(String key);
}
这样Redis里面就存储了每天产生的最大序列号。
能够依据日期、业务码等统计相关信息。