代码说

code is poetry

代码说    
碎碎念:等不到天黑,烟火不会太完美,回忆烧成灰,还是等不到结尾。  换一换

利用mysql的唯一约束进行高并发下的抽奖控制

作者:coderzheng 发布于:2016-9-27 14:21 Tuesday 分类:php  阅读模式

场景描述:根据概率抽奖,其中iphone7的中奖几率为1/10...0。iphone7有且仅有一台,因此iphone7一旦被抽中,之后的用户抽奖时,iphone7的中奖概率一律为0。
我们来看一种常规的解决方案:建立表prize_log,表结构如下:
CREATE TABLE `prize_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT, #自增ID
  `prize_id` tinyint(4) DEFAULT '0', #所得奖项ID
  `used` int(11) DEFAULT '0', #已中奖次数
  `amount` int(11) DEFAULT '0', #总中奖次数
  `ymd` int(11) DEFAULT '0', #中奖日期
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
假设iphone7这个奖项的编号为6,流程图如下:

当然,我们忽略了一些细节:中奖之后程序会更新中奖记录表。上面的算法表面上看可以满足要求,但是在并发下却会出现问题。
原因是,高并发下是可能出现两个人或者多人同一时间都抽中iphone7这种情况的。出现这种情况的原因是,程序在处理抽奖时
仅仅依靠从数据库中读取的数据来进行判断,但是读操作只和写操作互斥,多个读操作之间却可以同时进行。
根据这条思路,我们重新调整了一下思路:
设置一个空表prize_log_t,表结构如下:
id int primary key auto_increament,
uid int,
ip varchar(24),
createtime int,
调整流程如下:

插入记录这里要注意利用主键的唯一约束,比如本例中指定prize_log_t表中的id字段值:
insert into prize_log_t values(1, 2386711, '127.0.0.1', 14789001212);
重新设计后,即使是高并发的情况,也不可能出现同一时间同时中iphone7的情况了。并且上述程序也能保证iphone7
被抽走后,以后iphone7被抽中的概率始终是0。
PS:关于抽奖概率算法请参见这篇文章:http://codespeaking.com/?post=195。请读者自行思考:本文利用数据库的唯一约束只能处理数目是一的情况,如果数目是二、三。。。呢?其实数目大于一的情形已经类似于秒杀场景下的精确控制了。







OveR.


标签: php

你可以发表评论、引用到你的网站或博客,或通过RSS 2.0订阅这个博客的所有文章。
上一篇: 把梳子卖给和尚  |  下一篇:解决CentOS6.5中启用samba服务后,win7中访问对应的文件夹没有浏览和创建文件权限的问题