php mysql 秒杀_redis+PHP实现高并发下秒杀数据入库的问题
在高并發(fā)下實(shí)現(xiàn)搶購(gòu)秒殺功能中,我有一個(gè)疑問(wèn),就是數(shù)據(jù)入庫(kù)的問(wèn)題,什么時(shí)候入庫(kù)。
設(shè)想思路:
1.判斷他搶購(gòu)成功了,立馬把生成的訂單數(shù)據(jù)寫入mysql訂單表,同時(shí)庫(kù)存表字段減少1;
2.判斷搶購(gòu)成功后,把用戶的user_id存入到redis的list列表里(比如:order,以u(píng)ser_id為值的列表)。然后再用crontab定時(shí)去一個(gè)一個(gè)插入到mysql訂單表里,同時(shí)庫(kù)存表字段減少1。
設(shè)想結(jié)果:
第一種思路,很好理解。簡(jiǎn)單的代碼實(shí)現(xiàn)如下:
$num=10; //假設(shè)庫(kù)存量
for($i=0;$i
\Redis::lpush('goods_store',1);//往goods_store列表中,
未搶購(gòu)之前這里應(yīng)該是默認(rèn)push 10個(gè)1進(jìn)去,當(dāng)然里面的1沒有實(shí)際意義
在搶購(gòu)之前,上面的代碼可以先執(zhí)行,把商品入隊(duì)。
搶購(gòu)時(shí)間到了:(大量用戶請(qǐng)求下面代碼執(zhí)行操作)
/* 模擬搶購(gòu)操作,搶購(gòu)前判斷redis隊(duì)列庫(kù)存量 */
$count=\Redis::lpop('goods_store');//lpop是原子性的,可以保證不會(huì)出現(xiàn)超賣現(xiàn)象。
if(!$count)
return '已經(jīng)搶光了';
/* 下面處理?yè)屬?gòu)成功后與mysql數(shù)據(jù)庫(kù)的交互 */
1. //根據(jù)規(guī)則生成訂單號(hào)(order_num),然后把相關(guān)的字段數(shù)據(jù)插入到訂單列表里
$data['order_num'] = *****************;
$data['user_id'] = ***;
$data['goods_id'] = **;
.......
$res = DB::table('order')->insert($data);
2. //減少num庫(kù)存字段
if($res)
DB::table('goods')->decrement('num', 1);,
上面的代碼中,當(dāng)用戶搶購(gòu)成功后,立馬把相關(guān)的訂單數(shù)據(jù)插入mysql訂單表中,同時(shí)庫(kù)存減少。現(xiàn)在我的疑問(wèn)來(lái)了,要是用這種思路的話,大并發(fā)下,要是多個(gè)用戶都同時(shí)進(jìn)入到插入數(shù)據(jù)到訂單列表和減少商品庫(kù)存量這個(gè)過(guò)程中,是不是也會(huì)造成并發(fā)操作導(dǎo)致服務(wù)器壓力瞬間過(guò)大,導(dǎo)致數(shù)據(jù)入庫(kù)不正確呢,比如說(shuō)存庫(kù)少減了一個(gè)(還是說(shuō)根據(jù)mysql增刪改查的原子性,并不會(huì)造成這樣的錯(cuò)誤)?。
針對(duì)上面搶購(gòu)成功后,立馬把相關(guān)的訂單數(shù)據(jù)插入mysql訂單表中,同時(shí)庫(kù)存減少,造成的數(shù)據(jù)庫(kù)服務(wù)器壓力過(guò)大的問(wèn)題;
于是有了第二種思路,把用戶的user_id存入到redis列表里(比如:order,以u(píng)ser_id為值的列表),在通過(guò)定時(shí)器crontab定時(shí)去從列表里一個(gè)一個(gè)取出user_id,生成相關(guān)的數(shù)據(jù)插入到mysql訂單表里,同時(shí)庫(kù)存表字段減少1。
代碼實(shí)現(xiàn)跟上面差不多,
/* 模擬搶購(gòu)操作,搶購(gòu)前判斷redis隊(duì)列庫(kù)存量 */
$count=\Redis::lpop('goods_store');//lpop是原子性的,可以保證不會(huì)出現(xiàn)超賣現(xiàn)象。
if(!$count)
return '已經(jīng)搶光了';
/* 下面處理?yè)屬?gòu)成功后把user_id存入列表 */
\Redis::lpush('order',user_id);
通過(guò)定時(shí)器crontab定時(shí)去下面的代碼
$user_id = \Redis::rpop('order',user_id);
1. //根據(jù)規(guī)則生成訂單號(hào)(order_num),然后把相關(guān)的字段數(shù)據(jù)插入到訂單列表里
$data['order_num'] = *****************;
$data['user_id'] = $user_id;
$data['goods_id'] = **;
.......
$res = DB::table('order')->insert($data);
2. //減少num庫(kù)存字段
if($res)
DB::table('goods')->decrement('num', 1);,
第二種思路,我的疑問(wèn)是,要是搶購(gòu)成功后,先把user_id存入隊(duì)列,再用定時(shí)器每隔一段時(shí)間去隊(duì)列里取數(shù)據(jù),然后生成相關(guān)的數(shù)據(jù)插入的mysql訂單表里,同時(shí)減少庫(kù)存。這樣是可以減輕數(shù)據(jù)庫(kù)服務(wù)器的壓力了。但是我的搶購(gòu)流程是這么設(shè)計(jì)的,用戶搶購(gòu)成功后,彈出//去支付按鈕//進(jìn)入訂單列表頁(yè)面(訂單列表頁(yè)數(shù)據(jù)是從mysql讀取出來(lái)的),由于使用定時(shí)器去執(zhí)行生成訂單數(shù)據(jù)然后再插入到mysql數(shù)據(jù)庫(kù),這個(gè)過(guò)程肯定會(huì)有延遲,要是用戶此時(shí)通過(guò)//去支付按鈕//進(jìn)入訂單列表頁(yè)面,發(fā)現(xiàn)訂單列表還沒有生成訂單數(shù)據(jù),那不是很悲催嗎?
【這樣設(shè)計(jì)搶購(gòu)流程是否合理,是不是不用進(jìn)入到訂單列表,直接點(diǎn)擊去支付,支付成功后,才生成訂單數(shù)據(jù)插入到數(shù)據(jù)庫(kù)呢】
以上就是我對(duì)兩種思路存在的疑惑,希望可以得到專業(yè)人士的講解,或者一起探討。
總結(jié)
以上是生活随笔為你收集整理的php mysql 秒杀_redis+PHP实现高并发下秒杀数据入库的问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 滤波器开发之五:基于算术平均的限幅滤波器
- 下一篇: linux cmake编译源码,linu