項(xiàng)目開(kāi)發(fā)時(shí),使用了兩套數(shù)據(jù)庫(kù),,開(kāi)發(fā)環(huán)境和上線環(huán)境,,數(shù)據(jù)庫(kù)表中大多采用了自增主鍵,,
比如:
id int unsigned primary key auto_increment,
但往往會(huì)碰到一些問(wèn)題,比如:
開(kāi)發(fā)環(huán)境中,,使用爬蟲(chóng)抓取一些數(shù)據(jù),,建立索引,再把數(shù)據(jù)遷移到上線環(huán)境,,會(huì)導(dǎo)致索引中的id和
上線環(huán)境數(shù)據(jù)庫(kù)中id對(duì)不上,,所以決定使用字符串作為主鍵。
那么問(wèn)題來(lái)了,,如何生成唯一的序列號(hào),?
格式按照:yyyyMMdd+兩位業(yè)務(wù)碼+10位的自增序列,
比如20150101**99**0000000001,。
思路:
獲得日期很簡(jiǎn)單,;
業(yè)務(wù)碼是調(diào)用服務(wù)傳入的參數(shù);
使用Redis來(lái)實(shí)現(xiàn)10位的自增序列的保存和自增,,使用serial.number:{日期}的格式來(lái)保存某一天的自增序列的值,;
主要代碼如下:
public interface SerialNumberService {
/**
* 序列號(hào)自增序列
*/
String SERIAL_NUMBER = "serial.number:";
/**
* 根據(jù)兩位業(yè)務(wù)碼字符串,生成一個(gè)流水號(hào),格式按照:<br/>
* yyyyMMdd{bizCode}{10位的自增序列號(hào)}
*
* @param bizCode
* 兩位,00-99
* @return 20位的序列號(hào)
* @throws ServiceException
*/
String generate(String bizCode) throws ServiceException;
//其實(shí),應(yīng)該對(duì)bizCode做白名單驗(yàn)證,以免惡意偽造
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 {
/** 檢查業(yè)務(wù)碼 */
boolean isLegal = isLegal(bizCode);
if (!isLegal) {
throw new ServiceException("bizCode參數(shù)不合法");
}
/** 獲取今天的日期:yyyyMMdd */
String date = TimeUtil.getToday();
/** 構(gòu)造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位的序列號(hào),長(zhǎng)度不足10位,前面補(bǔ)0
*
* @param seq
* @return
*/
public static String getSequence(long seq) {
String str = String.valueOf(seq);
int len = str.length();
if (len >= DEFAULT_LENGTH) {// 取決于業(yè)務(wù)規(guī)模,應(yīng)該不會(huì)到達(dá)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();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
只聲明了RedisDao接口,,可以使用Jedis客戶(hù)端來(lái)實(shí)現(xiàn),。
public interface RedisDao {
String get(String key);
/**
* 自增,+1,返回增加后的值
*
* @param key
* @return
*/
long incr(String key);
}
|