以购买商品举例:
从数据库获取库存的数量.
检查一下库存的数量是否充足.
库存的数量减去买家购买的数量 (以每个用户购买一个为例).
最后完成购买.
仅仅这几行逻辑代码在并发的情况下会出现问题, 自己可以想象一下.
这里暂时就不测试了, 下面会针对并发的处理给出测试结果.
创建表:
- CREATE TABLE `warehouse` (
- `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
- `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
- PRIMARY KEY (`id`)
- ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
第一种方案, 使用 Mysql 的锁 (跟表引擎没有关系).
共享锁: 所有人可以读一个资源, 但只有获取锁的人可以操作;
排它锁: 只有获得所的对象可以操作资源, 其他的不能操作, 读都不可以.
语法:
LOCK TABLE a READ,b WRITE,c READ,d WRITE;(可以锁多张表, 在锁表的过程中只能操作被锁的表, 不能操作其他表).
- UNLOCK TABLES;(释放表).
- @$mysql = mysql_connect('localhost','root','');
- mysql_query('set names utf8');
- mysql_select_db('test');
- mysql_query('LOCK TABLE `warehouse` WRITE'); // 锁表之后同一时间只有一个人能操作, 也就是只有一个人能获取到锁
- $sql = 'SELECT `stock` FROM warehouse';
- $res = mysql_query($sql);
- $row= mysql_fetch_array($res);
- $stock = $row[0];
- if( $stock <1) {
- die('库存不足');
- }else{
- $new_stock = intval($stock - 1);
- mysql_query('UPDATE warehouse SET `stock` ='.$new_stock);
- mysql_query('UPDATE TABLES');
- }
锁表的缺点是: 会出现阻塞, 如果同时锁多张表的话, 还会影响整个网站相关表的加载.
第二种方案, 使用 PHP 的文件锁.
特点: 当调用 flock 锁一个文件时, 如果没有获取锁, 直接返回 FALSE, 不会出现阻塞.
排它锁: flock($fp,LOCK_EX);
共享锁: flock($fp,LOCK_SH);
释放锁: flock($fp,LOCK_UN);
- @$mysql = mysql_connect('localhost','root','');
- mysql_query('set names utf8');
- mysql_select_db('test');
- $fp = fopen('./lock.txt','r');
- $try = 10; // 声明一个变量表示要获取的次数, 防止死循环
- do{
- $lock = flock($fp, LOCK_EX);
- if(!$lock)
- usleep(5000); // 如果没有获取到锁, 释放 CPU, 休息 5000 毫秒
- }while(!$lock && --$try>=0 );
- if($lock) {
- $sql = 'SELECT `stock` FROM warehouse';
- $res = mysql_query($sql);
- $row = mysql_fetch_array($res);
- $stock = $row[0];
- if( $stock <1) {
- die('库存不足');
- }else{
- $new_stock = intval($stock - 1);
- mysql_query('UPDATE warehouse SET `stock` ='.$new_stock);
- }
- flock($fp, LOCK_UN);
- fclose($fp);
- }else{ die('系统繁忙!'); }
第三种方案, 简单的 SQL 语句就可以避免仓库为负数.
- @$mysql = mysql_connect('localhost','root','');
- mysql_query('set names utf8');
- mysql_select_db('test');
- mysql_query('UPDATE warehouse SET `stock` = `stock` -1 WHERE `stock`> 0'); // 可以避免库存为负数
来源: http://www.bubuko.com/infodetail-2652055.html