標籤:流水號 序號 日期 自增 redis
項目開發時,使用了兩套資料庫,開發環境和上線環境,資料庫表中大多採用了自增主鍵,
比如:
id int unsigned primary key auto_increment,
但往往會碰到一些問題,比如:
開發環境中,使用爬蟲抓取一些資料,建立索引,再把資料移轉到上線環境,會導致索引中的id和
上線環境資料庫中id對不上,所以決定使用字串作為主鍵。
那麼問題來了,如何產生唯一的序號?
格式按照:yyyyMMdd+兩位業務碼+10位的自增序列,
比如20150101**99**0000000001。
思路:
獲得日期很簡單;
業務碼是調用服務傳入的參數;
使用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; 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; }}@Servicepublic 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介面,可以使用Jedis用戶端來實現。
public interface RedisDao { String get(String key); /** * 自增,+1,返回增加後的值 * * @param key * @return */ long incr(String key);}
流水號的產生(日期+業務碼+自增序列)