Heim  >  Artikel  >  Backend-Entwicklung  >  So verwenden Sie die Redis-Sperre, um Probleme mit hoher Parallelität zu lösen

So verwenden Sie die Redis-Sperre, um Probleme mit hoher Parallelität zu lösen

不言
不言Original
2018-09-10 14:45:543361Durchsuche

Das Problem der hohen Parallelität ist ein Problem, auf das wir häufig stoßen. Wie kann das Problem der hohen Parallelität gelöst werden? In diesem Artikel wird die Verwendung von Redis-Sperren zur Lösung von Problemen mit hoher Parallelität vorgestellt.

Hier verwenden wir hauptsächlich den Befehl setnx von Redis, um eine hohe Parallelität zu bewältigen.

setnx hat zwei Parameter. Der erste Parameter stellt den Schlüssel dar. Der zweite Parameter stellt den Wert dar. Wenn der aktuelle Schlüssel nicht vorhanden ist, wird der aktuelle Schlüssel eingefügt, wobei der zweite Parameter als Wert verwendet wird. Rückkehr 1. Wenn der aktuelle Schlüssel existiert, wird 0 zurückgegeben.

Bestandstabelle erstellen

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

Anfangsbestand auf 10 setzen

Bestelltabelle erstellen

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

Test ohne Sperre

$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 Der Test simulierte Parallelität und stellte fest, dass die Bestandsaufnahme korrekt war.

mysql> select * from storage;
+----+--------+
| id | number |
+----+--------+
|  1 |      0 |
+----+--------+
1 row in set (0.00 sec)

Beim Blick auf die Bestelltabelle

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)

wurde festgestellt, dass mehrere Bestellungen mit denselben Bestandsdaten ausgeführt werden, was zu überverkauften Konditionen führen kann.

Ändern Sie den Code und fügen Sie eine Redis-Sperre zur Datenkontrolle hinzu

<?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
{
    //加锁不成功执行其他操作。
}

Führen Sie den ab Test erneut durch und überprüfen Sie die Testergebnisse

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)

Sie haben festgestellt, dass die Bestelltabelle nicht funktioniert die gleichen Bestandsdaten. Daher kann die Verwendung der Redis-Sperre eine hohe Parallelität effektiv bewältigen.

Tatsächlich besteht keine Notwendigkeit, die Ablaufzeit beim Sperren zu beurteilen. Um einen Deadlock zu vermeiden, fügen wir hier eine Beurteilung der Ablaufzeit hinzu. Löschen Sie die Sperre aktiv, wenn sie abläuft.

Verwandte Empfehlungen:

PHP verwendet Dateisperren, um Probleme mit hoher Parallelität zu lösen

Wie wäre es mit der Verwendung von Redis zum Speichern von PHP-Sitzungen? Lösen Sie das Problem der Parallelität und Konsistenz

Das obige ist der detaillierte Inhalt vonSo verwenden Sie die Redis-Sperre, um Probleme mit hoher Parallelität zu lösen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn