重慶分公司,新征程啟航
為企業(yè)提供網(wǎng)站建設(shè)、域名注冊、服務器等服務
為企業(yè)提供網(wǎng)站建設(shè)、域名注冊、服務器等服務
SQL server中可以用sequence來實現(xiàn)訂單號的自動生成。
創(chuàng)新互聯(lián)建站是專業(yè)的淄博網(wǎng)站建設(shè)公司,淄博接單;提供成都網(wǎng)站設(shè)計、網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務;采用PHP框架,可快速的進行淄博網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!
例如創(chuàng)建如下序列:
create sequence orderSeq
as bigint --數(shù)據(jù)類型
start with 100000 --開始值
increment by 1 --增量
minvalue 1 --最小值
maxvalue 1000000--最大值
no cycle --不循環(huán)
cache 3 --設(shè)置cache大小為3
這樣訂單號就會從100000開始每次自增1生成。
由于我在工作中遇到這個問題,借此與大家分享一下各大電子商務網(wǎng)站訂單號的生成方式。
訂單號概念
它是您在購物網(wǎng)站購物后獲得的訂單號,記錄的是購物訂單信息。
作用
在您需要與購物網(wǎng)站進行訂單查詢等操作時,需要給購物網(wǎng)站提供商家訂單號。
幾種下單途徑?
web網(wǎng)站下單
打電話到呼叫中心(CallCenter)下單
手機wap下單
如果采用單數(shù)據(jù)庫來存儲的話,隨著訂單量的增加,單庫的寫壓力增大,造成數(shù)據(jù)庫服務器性能下降。一般會采用分庫來緩解數(shù)據(jù)庫服務器的壓力。
那么怎么來進行分庫呢?
web來源訂單,存入web訂單庫。
CallCenter來源訂單,存入CallCenter訂單庫。
wap來源訂單,存入wap訂單庫。
最終,將這三種類型的數(shù)據(jù)庫同步到訂單主庫中。
問題來了,怎么把不同的訂單同步到訂單主庫呢?
電商網(wǎng)站一般利用訂單號來作為訂單表的主鍵。因此,我們必須保證訂單號不重復,才能將訂單安全的同步到訂單主庫中。
訂單命名規(guī)定唯一性
這個大家都明白,主要保證訂單號不重復。
安全性
訂單編號不能透露你公司的真實運營信息,比如你的訂單就是流水號的話,那么別人就可以從訂單號推測出你公司的整體運營概括了。所以訂單編碼必須是除了你們公司少部分人外,其他人基本看不懂的。可以參考京東和淘寶的編碼規(guī)則。
不能使用大規(guī)模隨機碼
因為大規(guī)模的隨機碼隨機生成,因為本身就沒有意義所以無所謂泄密了。但是事實上這種編碼規(guī)則在實現(xiàn)上會有很大問題的。隨機碼滿足第二點安全性要求,為了滿足唯一性,那就得在生成隨機碼的時候?qū)Ρ葰v史數(shù)據(jù)是否有重復,如果你的訂單數(shù)量到達了十萬次,你每次生成訂單編碼時就得對比十萬條歷史數(shù)據(jù)。
隨機碼就不能在編碼中使用了嗎?小規(guī)模的隨機碼是可以使用的,比如2~3位,這種隨機碼一般都是和流水號等結(jié)合使用,主要作用是為了隱藏流水號的真實數(shù)據(jù)而進行使用的。
防止并發(fā)
主要針對編碼中有時間的設(shè)定。
控制位數(shù)
訂單號的作用就是便于查詢。一般正常使用場景應該是訂單出異狀或者退貨的時候,用戶將訂單號報給客服,由客服進行查詢。所以一般在10~15位為好。目前京東11位,淘寶16位。
怎么保證訂單號的唯一性訂單號命名規(guī)則來生成
比如“業(yè)務編碼 + 時間戳 + 機器編號[前4位] + 隨機4位數(shù) + 毫秒數(shù)”。
說明:業(yè)務編碼(OrderType: Web=1 CallCenter=2 Wap=3) 機器編號(用來表示由那臺服務器生成的訂單)
偽代碼如下:
缺點:這種方式在高并發(fā)下會頻繁更新訂單量記錄表,很容易產(chǎn)生鎖表。但是鎖表問題也是可以解決的,加一層緩存。
全局訂單號數(shù)據(jù)池來生成
數(shù)據(jù)庫創(chuàng)建一個訂單號數(shù)據(jù)庫表(order_id_generator);利用python腳本生成一批訂單號,將這批訂單號存入到order_id_generator表中。生成訂單時,會首先調(diào)用事務GET_ORDER_ID_FOR_REGISTER,獲得當前訂單號,再生成訂單。這樣就保證了子庫訂單號不會重復。
數(shù)據(jù)庫代碼如下:
偽代碼如下:
總結(jié)
訂單號的生成方案,需要根據(jù)目前的訂單量而定;因為各種方案都有各自的使用場景。
首先,訂單號有3個性質(zhì):1.唯一性 2.不可推測性 3.效率性
唯一性和不可推測性不用說了,效率性是指不能頻繁的去數(shù)據(jù)庫查詢以避免重復。
況且滿足這些條件的同時訂單號還要足夠的短。
我在java下定制的訂單號生成方式如下:
int r1=(int)(Math.random()*(10));//產(chǎn)生2個0-9的隨機數(shù)
int r2=(int)(Math.random()*(10));
long now = System.currentTimeMillis();//一個13位的時間戳
String paymentID =String.valueOf(r1)+String.valueOf(r2)+String.valueOf(now);// 訂單ID
目前規(guī)則來看,兩個人在同一微秒提交訂單重復的概率為1%
訂單效果:251393292999921
望采納!
這個只能程序做的。數(shù)據(jù)庫只提供了數(shù)據(jù)的插入,修改,刪除和查詢等操作,沒有提供完備的計算功能
Getkey(tableName)就是調(diào)用存錯過程GetID的方法,@Size是固定的還是應該作為參數(shù)傳進來?
用存儲過程生成流水號是很常用的,這里以生成訂單編號的流水號作為示例。(新的一天的流水號從1開始,如:今天的訂單編號是CD2013010900014,下一個訂單編號將是CD2013010900015;明天的訂單編號將從CD2013011000001開始)
生成規(guī)則:2位前綴+年月日+5位流水號 或者 2位前綴+年月日時分+5位流水號 或者 2位前綴+年月日時分秒+5位流水號。
測試訂單表(test_orders):
[sql] view plain copy
CREATE TABLE `test_orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orderNo` varchar(25) NOT NULL DEFAULT '',
`orderName` char(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8
生成訂單編號的存儲過程(generate_orderNo):
[sql] view plain copy
CREATE DEFINER=PROCEDURE `generate_orderNo`(in orderNamePre char(2), in num int, out newOrderNo varchar(25))
BEGIN
DECLARE currentDate varCHAR (15) ;-- 當前日期,有可能包含時分秒
DECLARE maxNo INT DEFAULT 0 ; -- 離現(xiàn)在最近的滿足條件的訂單編號的流水號最后5位,如:SH2013011000002的maxNo=2
-- DECLARE l_orderNo varCHAR (25) ;-- 新生成的訂單編號
-- DECLARE oldDate DATE ;-- 離現(xiàn)在最近的滿足條件的訂單編號的日期
DECLARE oldOrderNo VARCHAR (25) DEFAULT '' ;-- 離現(xiàn)在最近的滿足條件的訂單編號
if num = 8 then -- 根據(jù)年月日生成訂單編號
SELECT DATE_FORMAT(NOW(), '%Y%m%d') INTO currentDate ;-- 訂單編號形式:前綴+年月日+流水號,如:SH2013011000002
elseif num = 14 then -- 根據(jù)年月日時分秒生成訂單編號
SELECT DATE_FORMAT(NOW(), '%Y%m%d%H%i%s') INTO currentDate ; -- 訂單編號形式:前綴+年月日時分秒+流水號,如:SH2013011010050700001,個人不推薦使用這種方法生成流水號
else -- 根據(jù)年月日時分生成訂單編號
SELECT DATE_FORMAT(NOW(), '%Y%m%d%H%i') INTO currentDate ;-- 訂單形式:前綴+年月日時分+流水號,如:SH20130110100900005
end if ;
SELECT IFNULL(orderNo, '') INTO oldOrderNo
FROM test_orders
WHERE SUBSTRING(orderNo, 3, num) = currentDate
AND SUBSTRING(orderNo, 1, 2) = orderNamePre
and length(orderNo) = 7 + num
ORDER BY id DESC LIMIT 1 ; -- 有多條時只顯示離現(xiàn)在最近的一條
IF oldOrderNo != '' THEN
SET maxNo = CONVERT(SUBSTRING(oldOrderNo, -5), DECIMAL) ;-- SUBSTRING(oldOrderNo, -5):訂單編號如果不為‘‘截取訂單的最后5位
END IF ;
SELECT
CONCAT(orderNamePre, currentDate, LPAD((maxNo + 1), 5, '0')) INTO newOrderNo ; -- LPAD((maxNo + 1), 5, '0'):如果不足5位,將用0填充左邊
INSERT INTO test_orders (orderNo, orderName) VALUES (newOrderNo, 'testNo') ; -- 向訂單表中插入數(shù)據(jù)
-- set newOrderNo = l_orderNo;
SELECT
newOrderNo ;
END
參數(shù)說明:orderNamePre:(輸入)訂單編號的前綴,這里設(shè)定為兩個字符
num:(輸入)將按什么規(guī)則生成流水號(生成規(guī)則有:年月日、年月日時分秒、年月日時分三種),可選的num有:8、12、14
newOrderNo:(輸出)新生成的訂單編號
生成中的一些說明在存儲過程中已經(jīng)寫得很明確了,這里不再重復。
調(diào)用存儲過程向表中插入數(shù)據(jù):
[sql] view plain copy
SET @orderNo = '';
CALL `generate_orderNo`('SH', 12, @orderNo);
SELECT @orderNo;