只用數(shù)據(jù)庫(kù)設(shè)計(jì)高效搶購(gòu)業(yè)務(wù)

不使用緩存(redis诺核、memcache),如何設(shè)計(jì)高效搶購(gòu)業(yè)務(wù)呢?
常見的搶購(gòu)業(yè)務(wù)主要有:
商品搶購(gòu)
券搶購(gòu)
紅包搶購(gòu)
今天咱們就談?wù)勅绾螌?duì)這些搶購(gòu)業(yè)務(wù)做統(tǒng)一設(shè)計(jì)祝钢,只使用Mysql做高并發(fā)活動(dòng)。
我們先看下面一張表若厚,分別標(biāo)出了這三類業(yè)務(wù)涉及到的核心數(shù)據(jù)量:

核心數(shù)據(jù)量

數(shù)據(jù)量 商品庫(kù)存 券庫(kù)存 紅包庫(kù)存 數(shù)據(jù)金額
1.總量 totalNum totalNum totalMoney 總金額
2.銷售量 sellNum sellNum sellMoney 領(lǐng)取金額
3.鎖定量 lockNum lockNum 0 鎖定金額
4.庫(kù)存量 stockNum stockNum stockMoney 庫(kù)存金額
5.退貨量 refundNum refundNum 0 0
6,庫(kù)存池 inventory inventory - -

我們?cè)倏聪逻@些業(yè)務(wù)涉及到的核心節(jié)點(diǎn)的數(shù)據(jù)量變化

核心數(shù)據(jù)量變化(變化量為n)

節(jié)點(diǎn)名稱 總量 銷售量 鎖定量 庫(kù)存量 退貨量
下單 totalNum不變 sellNum不變 lockNum+n stockNum不變 refundNum不變
取消訂單 totalNum不變 sellNum不變 lockNum-n stockNum不變 refundNum不變
支付 totalNum不變 sellNum+n lockNum-n stockNum-n refundNum不變
核銷 totalNum不變 sellNum不變 lockNum不變 stockNum不變 refundNum不變
退款 totalNum不變 sellNum-n(或不變) lockNum不變 stockNum+n(或不變) refundNum+n

節(jié)點(diǎn)設(shè)計(jì)

我們知道拦英,每個(gè)操作節(jié)點(diǎn)最少可對(duì)應(yīng)一個(gè)操作。而我們?yōu)榱吮WC接口效率最高测秸,我們需要盡量少的使用sql操作疤估,如果每個(gè)接口只有一次數(shù)據(jù)操作那是最好的灾常。
但是,每個(gè)接口的邏輯可能都會(huì)涉及到若干數(shù)據(jù)業(yè)務(wù)操作铃拇,而我們?yōu)榱四茏屵@些搶購(gòu)業(yè)務(wù)性能盡量好钞瀑,那我們就要盡量把接口原子化設(shè)計(jì)。而在這些接口中慷荔,下單操作時(shí)重中之重雕什,只要把這個(gè)下單接口設(shè)計(jì)好了,后續(xù)流程基本都沒啥大問題显晶。

下單接口設(shè)計(jì)

那我們來分析一下下單接口的設(shè)計(jì)業(yè)務(wù):
檢查庫(kù)存是否夠用
防止并發(fā)超賣
鎖庫(kù)存
等等...
那這些要求改如何同時(shí)滿足呢贷岸?那就要我們盡量合理使用核心數(shù)據(jù)量了!
那我們?cè)谠O(shè)計(jì)庫(kù)存表的時(shí)候吧碾,盡量把總量凰盔、銷售量、鎖定量倦春、庫(kù)存量放到一起户敬,可以如下設(shè)計(jì):

CREATE TABLE `goods_stock` (
  `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `SPU_ID` bigint(20) NOT NULL DEFAULT '0' COMMENT '商品SPU_ID',
  `SKU_ID` bigint(20) NOT NULL DEFAULT '0' COMMENT '商品SKU ID',
  `STOCK_LEFT_NUM` int(11) NOT NULL DEFAULT '0' COMMENT '剩余庫(kù)存數(shù)量',
  `STOCK_SALE_NUM` int(11) NOT NULL DEFAULT '0' COMMENT '售賣庫(kù)存數(shù)量',
  `STOCK_LOCK_NUM` int(11) NOT NULL DEFAULT '0' COMMENT '被鎖定的庫(kù)存數(shù)量',
  `STOCK_TOTAL_NUM` int(11) NOT NULL DEFAULT '0' COMMENT 'SKU總庫(kù)存量,0表示不限制庫(kù)存',
  `STATUS` tinyint(4) NOT NULL DEFAULT '0' COMMENT '本條記錄狀態(tài),0-有效睁本,1-無效',
  `CREATE_TIME` datetime NOT NULL COMMENT '創(chuàng)建時(shí)間',
  `UPDATE_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',
  `VERSION` int(11) NOT NULL DEFAULT '0' COMMENT '樂觀鎖版本號(hào)',
  PRIMARY KEY (`ID`),
  KEY `IDX_SPU_ID` (`SPU_ID`),
  KEY `IDX_SKU_ID` (`SKU_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品SKU庫(kù)存表';

其他字段在實(shí)例中省略了尿庐。
我們看看如何使用這一張表滿足上述要求:
1,檢查庫(kù)存是否夠用:

STOCK_LEFT_NUM >= n

2呢堰,防止并發(fā)超賣:
利用數(shù)據(jù)庫(kù)行級(jí)鎖防并發(fā)

WHERE SKU_ID = ${sku_id}

3抄瑟,鎖庫(kù)存:

STOCK_LOCK_NUM = STOCK_LOCK_NUM + n

那么,具體的下單枉疼、取消訂單皮假、支付等業(yè)務(wù)節(jié)點(diǎn)就可以如下實(shí)現(xiàn):
1,下單

UPDATE `goods_stock`
  SET `STOCK_LOCK_NUM` = `STOCK_LOCK_NUM` + ${lockNum}
  WHERE `STOCK_LEFT_NUM` <![CDATA[ >= ]]> ${lockNum}
    AND `SKU_ID` = ${skuId}
    AND ${lockNum} <![CDATA[ > ]]> 0

當(dāng)該操作執(zhí)行成功骂维,再處理其他邏輯惹资;如果失敗,就直接返回下單失敗航闺。
2褪测,取消訂單

UPDATE `goods_stock`
  SET `STOCK_LOCK_NUM` = `STOCK_LOCK_NUM` - ${lockNum}
  WHERE `SKU_ID` = ${skuId}
    AND ${lockNum} <![CDATA[ > ]]> 0

3,支付訂單

UPDATE `goods_stock`
  SET `STOCK_LOCK_NUM` = `STOCK_LOCK_NUM` - ${lockNum},
      `STOCK_SALE_NUM` = `STOCK_SALE_NUM` + ${lockNum},
      `STOCK_LEFT_NUM` = `STOCK_LEFT_NUM` - ${lockNum}
  WHERE `STOCK_LOCK_NUM` <![CDATA[ >= ]]> ${lockNum}
    AND `SKU_ID` = ${skuId}
    AND ${lockNum} <![CDATA[ > ]]> 0

目前MySql+SD硬盤的話潦刃,MySql事務(wù)并發(fā)量達(dá)到2000是沒啥壓力的侮措,所以一般并發(fā)2000左右的都可以直接使用MySql數(shù)據(jù)庫(kù)設(shè)計(jì)業(yè)務(wù)邏輯,無需使用Redis緩存乖杠。
這里只是給出了商品庫(kù)存核心邏輯分扎,券和其類似,不過還多一點(diǎn)庫(kù)存池(存放券碼)胧洒,其實(shí)這個(gè)可以放到后臺(tái)去處理了畏吓;紅包比這個(gè)更簡(jiǎn)單环揽,只有下單(領(lǐng)紅包)操作。
-End-

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末庵佣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子汛兜,更是在濱河造成了極大的恐慌巴粪,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粥谬,死亡現(xiàn)場(chǎng)離奇詭異肛根,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)漏策,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門派哲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掺喻,你說我怎么就攤上這事芭届。” “怎么了感耙?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵褂乍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我即硼,道長(zhǎng)逃片,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任只酥,我火速辦了婚禮褥实,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘裂允。我一直安慰自己损离,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布叫胖。 她就那樣靜靜地躺著草冈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瓮增。 梳的紋絲不亂的頭發(fā)上怎棱,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音绷跑,去河邊找鬼拳恋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛砸捏,可吹牛的內(nèi)容都是我干的谬运。 我是一名探鬼主播隙赁,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼梆暖!你這毒婦竟也來了伞访?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤轰驳,失蹤者是張志新(化名)和其女友劉穎厚掷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體级解,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冒黑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勤哗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抡爹。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖芒划,靈堂內(nèi)的尸體忽然破棺而出冬竟,到底是詐尸還是另有隱情,我是刑警寧澤民逼,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布诱咏,位于F島的核電站,受9級(jí)特大地震影響缴挖,放射性物質(zhì)發(fā)生泄漏袋狞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一映屋、第九天 我趴在偏房一處隱蔽的房頂上張望苟鸯。 院中可真熱鬧,春花似錦棚点、人聲如沸早处。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砌梆。三九已至,卻和暖如春贬循,著一層夾襖步出監(jiān)牢的瞬間咸包,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工杖虾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烂瘫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓奇适,卻偏偏與公主長(zhǎng)得像坟比,于是被迫代替她去往敵國(guó)和親芦鳍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容