争怎路由网/网站教程/内容

如何使用Redis锁处理高并发问题

网站教程2024-04-15 阅读
网页的本质就是超级文本标记语言,通过结合使用其他的Web技术(如:脚本语言、公共网关接口、组件等),可以创造出功能强大的网页。因而,超级文本标记语言是万维网(Web)编程的基础,也就是说万维网是建立在超文本基础之上的。超级文本标记语言之所以称为超文本标记语言,是因为文本中包含了所谓“超级链接”点。
高并发问题是我们经常可以遇到的问题,那么该如何解决高并发这个问题呢?本篇文章介绍的内容就是利用Redis锁解决高并发问题,一起来看看吧。

这里我们主要利用Redis的setnx的命令来处理高并发。

setnx 有两个参数。第一个参数表示键。第二个参数表示值。如果当前键不存在,那么会插入当前键,将第二个参数做为值。返回 1。如果当前键存在,那么会返回0。

创建库存表

CREATE TABLE `storage` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `number` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

设置初始库存为10

创建订单表

CREATE TABLE `order` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `number` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

测试不用锁的时候

$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
$sql="select `number` from  storage where id=1 limit 1";
$res = $pdo->query($sql)->fetch();
$number = $res['number'];
if($number>0)
{
    $sql ="insert into `order`  VALUES (null,$number)";

    $order_id = $pdo->query($sql);
    if($order_id)
    {

        $sql="update storage set `number`=`number`-1 WHERE id=1";
        $pdo->query($sql);
    }
}

ab测试模拟并发,发现库存是正确的。

mysql> select * from storage;
+----+--------+
(专业提供视频软件下载)

id (专业提供视频软件下载)

number (专业提供视频软件下载)

+----+--------+ (专业提供视频软件下载)

1 (专业提供视频软件下载)

0 (专业提供视频软件下载)

+----+--------+ 1 row in set (0.00 sec)

在来看订单表

mysql> select * from `order`;
+----+--------+
(专业提供视频软件下载)

id (专业提供视频软件下载)

number (专业提供视频软件下载)

+----+--------+ (专业提供视频软件下载)

1 (专业提供视频软件下载)

10 (专业提供视频软件下载)

(专业提供视频软件下载)

2 (专业提供视频软件下载)

10 (专业提供视频软件下载)

(专业提供视频软件下载)

3 (专业提供视频软件下载)

9 (专业提供视频软件下载)

(专业提供视频软件下载)

4 (专业提供视频软件下载)

7 (专业提供视频软件下载)

(专业提供视频软件下载)

5 (专业提供视频软件下载)

6 (专业提供视频软件下载)

(专业提供视频软件下载)

6 (专业提供视频软件下载)

5 (专业提供视频软件下载)

(专业提供视频软件下载)

7 (专业提供视频软件下载)

5 (专业提供视频软件下载)

(专业提供视频软件下载)

8 (专业提供视频软件下载)

5 (专业提供视频软件下载)

(专业提供视频软件下载)

9 (专业提供视频软件下载)

4 (专业提供视频软件下载)

(专业提供视频软件下载)

10 (专业提供视频软件下载)

1 (专业提供视频软件下载)

+----+--------+ 10 rows in set (0.00 sec)

发现存在几个订单都是操作的同一个库存数据,这样就可能引起超卖的情况。

修改代码加入redis锁进行数据控制

<?php
/**
 * Created by PhpStorm.
 * User: daisc
 * Date: 2018/7/23
 * Time: 14:45
 */
class Lock
{
    private static $_instance ;
    private   $_redis;
    private function __construct()
    {
        $this->_redis =  new Redis();
        $this->_redis ->connect('127.0.0.1');
    }
    public static function getInstance()
    {
        if(self::$_instance instanceof self)
        {
            return self::$_instance;
        }
        return self::$_instance = new  self();
    }

    /**
     * @function 加锁
     * @param $key 锁名称
     * @param $expTime 过期时间
      */
    public function set($key,$expTime)
    {
        //初步加锁
        $isLock = $this->_redis->setnx($key,time()+$expTime);
        if($isLock)
        {
            return true;
        }
        else
        {
            //加锁失败的情况下。判断锁是否已经存在,如果锁存在切已经过期,那么删除锁。进行重新加锁
            $val = $this->_redis->get($key);
            if($val&&$val<time())
            {
                $this->del($key);
            }
            return  $this->_redis->setnx($key,time()+$expTime);
        }
    }


    /**
     * @param $key 解锁
     */
    public function del($key)
    {
        $this->_redis->del($key);
    }

}



$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
$lockObj = Lock::getInstance();
//判断是能加锁成功
if($lock = $lockObj->set('storage',10))
{
    $sql="select `number` from  storage where id=1 limit 1";
    $res = $pdo->query($sql)->fetch();
    $number = $res['number'];
    if($number>0)
    {
        $sql ="insert into `order`  VALUES (null,$number)";

        $order_id = $pdo->query($sql);
        if($order_id)
        {

            $sql="update storage set `number`=`number`-1 WHERE id=1";
            $pdo->query($sql);
        }
    }
    //解锁
    $lockObj->del('storage');

}
else
{
    //加锁不成功执行其他操作。
}

再次进行ab测试,查看测试结果

mysql> select * from `order`;
+----+--------+
(专业提供视频软件下载)

id (专业提供视频软件下载)

number (专业提供视频软件下载)

+----+--------+ (专业提供视频软件下载)

1 (专业提供视频软件下载)

10 (专业提供视频软件下载)

(专业提供视频软件下载)

2 (专业提供视频软件下载)

9 (专业提供视频软件下载)

(专业提供视频软件下载)

3 (专业提供视频软件下载)

8 (专业提供视频软件下载)

(专业提供视频软件下载)

4 (专业提供视频软件下载)

7 (专业提供视频软件下载)

(专业提供视频软件下载)

5 (专业提供视频软件下载)

6 (专业提供视频软件下载)

(专业提供视频软件下载)

6 (专业提供视频软件下载)

5 (专业提供视频软件下载)

(专业提供视频软件下载)

7 (专业提供视频软件下载)

4 (专业提供视频软件下载)

(专业提供视频软件下载)

8 (专业提供视频软件下载)

3 (专业提供视频软件下载)

(专业提供视频软件下载)

9 (专业提供视频软件下载)

2 (专业提供视频软件下载)

(专业提供视频软件下载)

10 (专业提供视频软件下载)

1 (专业提供视频软件下载)

+----+--------+ 10 rows in set (0.00 sec)

发现订单表没有操作同一个库存数据的情况。所以利用redis锁是可以有效的处理高并发的。

这里在加锁的时候其实是可以不需要判断过期时间的,这里我们为了避免造成死锁,所以加一个过期时间的判断。当过期的时候主动删除该锁。

相关推荐:

php利用文件锁来解决高并发问题

使用Redis来存储PHP的session如何解决并发一致性的问题

以上就是如何利用Redis锁解决高并发问题的详细内容,更多请关注php中文网其它相关文章!


网站建设是一个广义的术语,涵盖了许多不同的技能和学科中所使用的生产和维护的网站。



……