php无法下单功能,PHP如何解决并发下单问题?(不一定是下单,举个例)
我們知道數(shù)據(jù)庫(kù)處理sql是一條條處理的,假設(shè)購(gòu)買商品的流程是這樣的:
sql1:查詢商品庫(kù)存
if(庫(kù)存數(shù)量 > 0)
{
//生成訂單...
sql2:庫(kù)存-1
}
當(dāng)沒有并發(fā)時(shí),上面的流程看起來是如此完美,假設(shè)同時(shí)兩個(gè)人下單,而庫(kù)存只有1個(gè)了,在sql1階段兩個(gè)人查詢到的庫(kù)存都是>0的,于是最終都執(zhí)行了sql2,庫(kù)存最后變?yōu)?1,超售了,要么補(bǔ)庫(kù)存,要么等用戶投訴吧。
解決這個(gè)問題比較好的方法是什么呢?
回復(fù)內(nèi)容:
我們知道數(shù)據(jù)庫(kù)處理sql是一條條處理的,假設(shè)購(gòu)買商品的流程是這樣的:
sql1:查詢商品庫(kù)存
if(庫(kù)存數(shù)量 > 0)
{
//生成訂單...
sql2:庫(kù)存-1
}
當(dāng)沒有并發(fā)時(shí),上面的流程看起來是如此完美,假設(shè)同時(shí)兩個(gè)人下單,而庫(kù)存只有1個(gè)了,在sql1階段兩個(gè)人查詢到的庫(kù)存都是>0的,于是最終都執(zhí)行了sql2,庫(kù)存最后變?yōu)?1,超售了,要么補(bǔ)庫(kù)存,要么等用戶投訴吧。
解決這個(gè)問題比較好的方法是什么呢?
用事務(wù)處理機(jī)制
數(shù)據(jù)表加鎖也行(如果你用InnoDB引擎就用行鎖;如果你用MyISAM引擎就用表鎖)
庫(kù)存字段改成unsigned int。
這樣的話不會(huì)<0,頂多就SQL執(zhí)行出錯(cuò)。
也可以用memcached/redis來緩存結(jié)果,從緩存中查詢。
1.MySQL數(shù)據(jù)庫(kù)加鎖,樂觀鎖 和 悲觀鎖
2.用隊(duì)列,排隊(duì)逐一去生成訂單
庫(kù)存緩存一般都是 有的吧,如果有并發(fā)需求。 還有就是加鎖,或者放到隊(duì)列執(zhí)行sql。
有種很笨的方法,已樓主的假設(shè)為例:
sql1:查詢商品庫(kù)存 (假設(shè)查出的庫(kù)存為10)
if(10 > 0)
{
//生成訂單...
sql2: 10 - 1 (此時(shí)庫(kù)存為9了)
//再校驗(yàn)庫(kù)存
sql3: 查詢商品庫(kù)存 == 9 (如果此時(shí)有并發(fā)情況,那查出來的庫(kù)存可能為8、7等,這時(shí)拋出異常,事務(wù)回滾,該筆訂單無效。)
}
處理高并發(fā)一般來說都會(huì)用到Redis,使用Redis的list數(shù)據(jù)結(jié)構(gòu)(高并發(fā)當(dāng)然要異步隊(duì)列咯)來存儲(chǔ)請(qǐng)求過來的訂單信息,然后啟用redis的事務(wù)機(jī)制(見:http://redis.io/topics/transactions),加入指定key的list前,判斷該list等長(zhǎng)度是否超過redis中保存的指定商品庫(kù)存值,如果超過則不操作,如果不超過,則進(jìn)行插入,插入之后,再次判斷該list的長(zhǎng)度是否超過redis中保存的指定商品的庫(kù)存值,如果超過則回滾,否則提交。
想問一下,并發(fā)量大的情況下,是怎么做的呢?
1.用事務(wù)保持操作原子性,
2.在修改庫(kù)存的時(shí)候先用select...for update把數(shù)據(jù)鎖好
update table set n = n-x where n >= x
不需要事務(wù),直接獲取affected row count來判斷是否扣成功,后到的那一條因?yàn)閚=0,affected row肯定為0
相關(guān)標(biāo)簽:php 并發(fā)
本文原創(chuàng)發(fā)布php中文網(wǎng),轉(zhuǎn)載請(qǐng)注明出處,感謝您的尊重!
總結(jié)
以上是生活随笔為你收集整理的php无法下单功能,PHP如何解决并发下单问题?(不一定是下单,举个例)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php制作曲线柱形图的框架,用GD图库生
- 下一篇: php扩展库加密如何解密,如何利用Mcr