首先,訂單號不適合用自增字段尊惰,因為會暴露一個網(wǎng)站的業(yè)務(wù)量讲竿。另外泥兰,通常在訂單在寫入數(shù)據(jù)庫之前,業(yè)務(wù)就需要用到訂單號了题禀。網(wǎng)上多數(shù)用microtime生成的時間戳生成唯一訂單序列號鞋诗,事實上高并發(fā)情況下有一定的重復(fù)幾率轻庆,就連uniqid($more_entropy參數(shù)為false)函數(shù)生成的序列號都可能有重復(fù)的可能(真坑爹)象对,而$more_entropy設(shè)置為true的話返回的序列號又太長了。
不依賴外部流水號忧风,完全靠時間戳和隨機數(shù)生成訂單號無法避免沖突秀仲,所以必須引入外部的流水號生成機制吃警。或使用數(shù)據(jù)庫啄育,或使用APC之類的緩存酌心。用APC之類的緩存存在一個問題,就是無法持久保持?jǐn)?shù)據(jù)挑豌,服務(wù)器重啟或者PHP宿主進程重啟都會清空流水號計數(shù)器安券,所以可以采取緩存+數(shù)據(jù)庫結(jié)合的模式——如果緩存中有流水號計數(shù)器數(shù)據(jù)則讀取并累加計數(shù),如果緩存中沒有流水號計數(shù)器從數(shù)據(jù)庫中還原計數(shù)器氓英。計數(shù)器可以每隔一段時間重置一次侯勉。
既然引入了自增流水號計數(shù)器,又會導(dǎo)致文章開頭的“德國坦克問題”铝阐,所以需要用skip32算法把流水號加密(https://github.com/nlenepveu/Skip32)址貌。
基于前文所述,得到如下的訂單號生成規(guī)則:
訂單號 = 日期前綴 + 加密流水號
// Skip32 算法加密密鑰
const ENCRYPTED_KEY = ‘xxxxxxxxxxxx';
// 使用 Wincache 作為流水號計數(shù)器緩存
function getOrderSerialNumber() {
$timestamp = time();
$datePrefix = date(‘ymd’, $timestamp);
// 如果流水號計數(shù)器數(shù)據(jù)不在緩存中徘键,則嘗試從數(shù)據(jù)庫中恢復(fù)
if (false === ($value = wincache_ucache_inc($datePrefix))) {
wincache_lock($datePrefix);
// 從數(shù)據(jù)庫中獲取今日的訂單數(shù)
$counter = getNumberOfOrdersTodayFromDatabase($timestamp);
$value = $counter + 1;
if (!wincache_ucache_add($datePrefix, $value, 60*60*24)) {
$value = wincache_ucache_inc($datePrefix);
}
wincache_unlock($datePrefix);
}
return $datePrefix.str_pad(Skip32::encrypt($datePrefix.ENCRYPTED_KEY, $value), 10, ‘0’, STR_PAD_LEFT);
}
文章轉(zhuǎn)載自: 技術(shù)鵬飛(https://www.itlipeng.cn)【本人尚未測試练对。只是拿來主義做個備用先】