我们来看一种常规的解决方案:建立表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.