redis秒杀简单实现

redis中的list类型是很好的一个队列,可以在秒杀的高并发中暂存缓存,然后过了秒杀峰期再去插入数据库,可以减轻服务器很大的压力。

基本思路:

先要做一个token防止表单重复提交,这里用session存一下token,然后前端先请求token的接口把token存到hidden的input中,提交时把token一并提交。这时后端判断token是否与session中的一致,一致就刷新token使其重复提交时与原token不一致。

接着后端接收到了传过来的用户名(这里应该是从session中拿的,作为演示就先用ajax发送)后,先在队列中判断列表的长度是否超过了设定的长度。没超过就正常写入redis,超过了就返回已经被抢光了。

秒杀完后就可以启动插入数据库的文件了,这里可以设置一个定时任务在秒杀结束后就自行开启。

下面是代码

addBook.php ---接受从前端传来的用户名和token,比较token以及判断队列是否满了

<?php
session_start();
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
//get post
$token = $_POST['token'];
$user = $_POST['user'];
//判断表单是否重复提交
if($_SESSION['token'] == $token){
	//重置token
	$_SESSION['token'] = uniqid();
	//判断队列长度
	if($redis->lLen('bookKill') < 10){
		//往redis中写入数据
		$redis->lPush('bookKill',$user);
		echo 'success!!';
	}else{
		echo 'you are late';
	}
}
else{
	echo 'token time out';
}


?>

save.php  ---保存至数据库的文件,循环10次从列表从右往左中取10条数据,redis列表中先插的数据在右边,新的数据在左边。数据库有错误信息就记录到log日志中。注意插入varchar类型的数据要加上单引号。

<?php
$con = mysqli_connect('127.0.0.1','root','','book');
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
for($i = 0;$i < 10;$i++){
	//获取列表中的值
	$data = $redis->Rpop('bookKill');
	//如果缓存中没数据了,但还不够10个,说明没有被秒杀完。就跳出循环。
	if($data == null)
		break;
	//插入数据库。记得username是字符串要加上单引号,不然无法插入又记不了日志。。。
	$sql = 'insert into book (`username`) values(\''.$data.'\');';
	//插入数据,如果有错误信息写入到log日志中
	if(!mysqli_query($con,$sql)){
		file_put_contents('./dbErrorLog.php', mysqli_error($con));
	}
}
?>

shop.html ---前端页面,使用ajax来发送数据

<!DOCTYPE html>
<html>
<head>
	<title></title>
	<meta charset="utf-8">
</head>
<body>
	<input type="hidden" id="token">
	<input type="text" id="user">
	<input type="button" id="button" value="抢购">
</body>
</html>
<script type="text/javascript" src="jqery.js"></script>
<script type="text/javascript">
	window.onload = function(){
		$.ajax({
			url:'./token.php',
			success:function(result){
				$("#token").val(result);
			}
		});
	}
	$("#button").click(function(){
		$.ajax({
			type:"post",
			url:'./addBook.php',
			data:{
				"user":$("#user").val(),
				"token":$("#token").val(),
			},
			success:function(result){
				alert(result);
			}
		})
	})	
</script>

token.php ---生成token,页面每次加载都要访问这个文件来获取最新token

<?php
session_start();
$token = uniqid() . 'book';
$_SESSION['token'] = $token;
echo $token;
?>

book.sql  --sql文件。实验原因就存了一个id一个用户名。数据表最好是InnoDb的支持事务。

SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `book`
--
CREATE DATABASE IF NOT EXISTS `book` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `book`;

-- --------------------------------------------------------

--
-- 表的结构 `book`
--

DROP TABLE IF EXISTS `book`;
CREATE TABLE IF NOT EXISTS `book` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL COMMENT '秒杀用户',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='库存表';
COMMIT;

猜你喜欢

转载自blog.csdn.net/xiaopan233/article/details/83120185