ホームページ バックエンド開発 PHPチュートリアル Redis ロックを使用して同時実行性の高い問題を解決する方法

Redis ロックを使用して同時実行性の高い問題を解決する方法

Sep 10, 2018 pm 02:45 PM
高い同時実行性

同時実行性が高いという問題はよく遭遇する問題ですが、同時実行性が高いという問題を解決するにはどうすればよいでしょうか?この記事では、同時実行性の問題を解決するための Redis ロックの使用法を紹介します。

ここでは主に Redis の setnx コマンドを使用して高い同時実行性を処理します。

setnx には 2 つのパラメータがあります。最初のパラメータはキーを表します。 2 番目のパラメータは値を表します。現在のキーが存在しない場合は、2 番目のパラメータを値として使用して、現在のキーが挿入されます。 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 セッションを保存する方法同時実行性と一貫性の問題を解決する

以上がRedis ロックを使用して同時実行性の高い問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PHP の高同時実行環境におけるリクエストのスケジューリングとタスクの割り当て方法 PHP の高同時実行環境におけるリクエストのスケジューリングとタスクの割り当て方法 Aug 10, 2023 pm 01:24 PM

PHP の高同時実行環境におけるリクエストのスケジューリングとタスクの割り当て方法 インターネットの急速な発展に伴い、バックエンド開発言語として広く使用されている PHP は、ますます多くの高同時実行リクエストに直面しています。同時実行性の高い環境では、リクエストのスケジューリングとタスクの割り当てをどのように実装するかが、開発中に解決する必要がある重要な問題となっています。この記事では、PHP の高同時実行環境におけるリクエストのスケジューリングとタスクの割り当て方法をいくつか紹介し、コード例を示します。 1. プロセス管理とタスクキュー PHP の高同時実行環境では、プロセス管理とタスクキューが一般的に使用される実装方法です。

FastAPI でリクエストの高い同時実行性と負荷分散を実現する方法 FastAPI でリクエストの高い同時実行性と負荷分散を実現する方法 Jul 31, 2023 pm 01:50 PM

FastAPI でリクエストの高い同時実行性と負荷分散を実現する方法 はじめに: インターネットの発展に伴い、Web アプリケーションの高い同時性が一般的な問題になりました。大量のリクエストを処理するときは、効率的なフレームワークとテクノロジーを使用して、システムのパフォーマンスとスケーラビリティを確保する必要があります。 FastAPI は、高い同時実行性と負荷分散の実現に役立つ高性能 Python フレームワークです。この記事では、FastAPI を使用してリクエストの高い同時実行性と負荷分散を実現する方法を紹介します。 Python3.7を使用します

高同時実行システムにおける Golang フレームワークのアーキテクチャ 高同時実行システムにおける Golang フレームワークのアーキテクチャ Jun 03, 2024 pm 05:14 PM

同時実行性の高いシステムの場合、Go フレームワークはパイプライン モード、Goroutine プール モード、メッセージ キュー モードなどのアーキテクチャ モードを提供します。実際の場合、同時実行性の高い Web サイトでは、Nginx プロキシ、Golang ゲートウェイ、Goroutine プール、およびデータベースを使用して、多数の同時リクエストを処理します。このコード例は、受信リクエストを処理するための Goroutine プールの実装を示しています。適切なアーキテクチャ パターンと実装を選択することで、Go フレームワークはスケーラブルで同時実行性の高いシステムを構築できます。

同時実行性の高いシナリオにおける PHP フレームワークのパフォーマンス 同時実行性の高いシナリオにおける PHP フレームワークのパフォーマンス Jun 06, 2024 am 10:25 AM

ベンチマーク テストによると、同時実行性の高いシナリオにおける PHP フレームワークのパフォーマンスは、Phalcon (RPS2200)、Laravel (RPS1800)、CodeIgniter (RPS2000)、および Symfony (RPS1500) です。実際の事例では、電子商取引 Web サイトのダブル イレブン イベント中に、Phalcon フレームワークが 1 秒あたり 3,000 件の注文を達成したことが示されています。

スウール開発機能向けの高同時実行TCP長時間接続処理スキル スウール開発機能向けの高同時実行TCP長時間接続処理スキル Aug 25, 2023 pm 10:01 PM

[タイトル] Swoole 開発機能のための高同時 TCP 長時間接続処理技術 [はじめに] インターネットの急速な発展に伴い、アプリケーションの同時処理に対する要求はますます高まっています。 Swoole は、PHP ベースの高性能ネットワーク通信エンジンとして、強力な非同期、マルチプロセス、およびコルーチン機能を提供し、アプリケーションの同時処理能力を大幅に向上させます。この記事では、Swoole 開発機能を使用して、同時実行性の高い TCP 長時間接続処理技術を処理する方法を紹介し、コード例を示して詳しく説明します。 【本文】1.スウォ

オブジェクト指向プログラミングにおける同時実行性の高いシナリオでの golang 関数の適用 オブジェクト指向プログラミングにおける同時実行性の高いシナリオでの golang 関数の適用 Apr 30, 2024 pm 01:33 PM

オブジェクト指向プログラミングの同時実行性の高いシナリオでは、Go 言語で関数が広く使用されています。 メソッドとしての関数: 関数を構造体にアタッチしてオブジェクト指向プログラミングを実装し、構造体データを便利に操作して特定の関数を提供できます。同時実行本体としての関数: 関数を goroutine 実行本体として使用して、タスクの同時実行を実装し、プログラムの効率を向上させることができます。コールバックとしての関数: 関数をパラメーターとして他の関数に渡し、特定のイベントまたは操作が発生したときに呼び出すことができるため、柔軟なコールバック メカニズムが提供されます。

swooleの開発機能を活用し、高同時性のネットワーク通信を実現 swooleの開発機能を活用し、高同時性のネットワーク通信を実現 Aug 08, 2023 pm 01:57 PM

Swooleの開発機能を活用して高同時性のネットワーク通信を実現 概要:Swooleは、PHP言語をベースとした高機能なネットワーク通信フレームワークで、コルーチン、非同期IO、マルチプロセスなどの機能を備えており、同時性の高い開発に適しています。ネットワークアプリケーション。この記事では、Swoole を使用して同時実行性の高いネットワーク通信機能を開発する方法といくつかのコード例を紹介します。はじめに インターネットの急速な発展に伴い、特に同時実行性の高いシナリオでは、ネットワーク通信の要件がますます高くなっています。従来の PHP 開発は同時処理能力が弱いという問題に直面しています

PHP の高同時処理におけるデータベースの読み取りおよび書き込みの最適化スキル PHP の高同時処理におけるデータベースの読み取りおよび書き込みの最適化スキル Aug 12, 2023 pm 04:31 PM

PHP におけるデータベースの読み取りおよび書き込みの最適化テクニック 高同時処理 インターネットの急速な発展に伴い、Web サイトの訪問数はますます増加しています。今日のインターネット アプリケーションでは、高度な同時処理が無視できない問題になっています。 PHP 開発では、データベースの読み取りおよび書き込み操作がパフォーマンスのボトルネックの 1 つになります。したがって、同時実行性の高いシナリオでは、データベースの読み取りおよび書き込み操作を最適化することが非常に重要です。以下では、PHP の高同時処理処理におけるデータベースの読み取りおよび書き込みの最適化手法をいくつか紹介し、対応するコード例を示します。接続プーリング技術を使用してデータベースに接続すると、

See all articles