成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

利用Redis鎖解決高并發(fā)問題

bitkylin / 1274人閱讀

摘要:創(chuàng)建庫存表設(shè)置初始庫存為創(chuàng)建訂單表測試不用鎖的時(shí)候測試模擬并發(fā),發(fā)現(xiàn)庫存是正確的。再次進(jìn)行測試,查看測試結(jié)果發(fā)現(xiàn)訂單表沒有操作同一個(gè)庫存數(shù)據(jù)的情況。所以利用鎖是可以有效的處理高并發(fā)的。當(dāng)過期的時(shí)候主動(dòng)刪除該鎖。

這里我們主要利用Redissetnx的命令來處理高并發(fā)。

setnx 有兩個(gè)參數(shù)。第一個(gè)參數(shù)表示鍵。第二個(gè)參數(shù)表示值。如果當(dāng)前鍵不存在,那么會(huì)插入當(dāng)前鍵,將第二個(gè)參數(shù)做為值。返回 1。如果當(dāng)前鍵存在,那么會(huì)返回0

創(chuàng)建庫存表

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

設(shè)置初始庫存為10

創(chuàng)建訂單表

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

測試不用鎖的時(shí)候

$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測試模擬并發(fā),發(fā)現(xiàn)庫存是正確的。

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)

發(fā)現(xiàn)存在幾個(gè)訂單都是操作的同一個(gè)庫存數(shù)據(jù),這樣就可能引起超賣的情況。

修改代碼加入redis鎖進(jìn)行數(shù)據(jù)控制

_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 過期時(shí)間
      */
    public function set($key,$expTime)
    {
        //初步加鎖
        $isLock = $this->_redis->setnx($key,time()+$expTime);
        if($isLock)
        {
            return true;
        }
        else
        {
            //加鎖失敗的情況下。判斷鎖是否已經(jīng)存在,如果鎖存在切已經(jīng)過期,那么刪除鎖。進(jìn)行重新加鎖
            $val = $this->_redis->get($key);
            if($val&&$valdel($key);
                return  $this->_redis->setnx($key,time()+$expTime);
            }
            return false;
        }
    }


    /**
     * @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
{
    //加鎖不成功執(zhí)行其他操作。
}

再次進(jìn)行ab測試,查看測試結(jié)果

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)

發(fā)現(xiàn)訂單表沒有操作同一個(gè)庫存數(shù)據(jù)的情況。所以利用redis鎖是可以有效的處理高并發(fā)的。

這里在加鎖的時(shí)候其實(shí)是可以不需要判斷過期時(shí)間的,這里我們?yōu)榱吮苊庠斐伤梨i,所以加一個(gè)過期時(shí)間的判斷。當(dāng)過期的時(shí)候主動(dòng)刪除該鎖。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/29398.html

相關(guān)文章

  • Redis分布式解決搶購問題

    摘要:廢話不多說,首先分享一個(gè)業(yè)務(wù)場景搶購。下面就是分布式鎖的解決方法。首先要加入的依賴,該類只有兩個(gè)功能,加鎖和解鎖,解鎖比較簡單,就是刪除當(dāng)前的鍵值對(duì)。這時(shí)繼續(xù)執(zhí)行,由于所以該線程獲取到鎖。 廢話不多說,首先分享一個(gè)業(yè)務(wù)場景-搶購。一個(gè)典型的高并發(fā)問題,所需的最關(guān)鍵字段就是庫存,在高并發(fā)的情況下每次都去數(shù)據(jù)庫查詢顯然是不合適的,因此把庫存信息存入Redis中,利用redis的鎖機(jī)制來控制...

    taoszu 評(píng)論0 收藏0
  • 秒殺系統(tǒng)優(yōu)化方案之緩存、隊(duì)列、設(shè)計(jì)思路

    摘要:一為什么難秒殺系統(tǒng)難做的原因庫存只有一份,所有人會(huì)在集中的時(shí)間讀和寫這些數(shù)據(jù)。又例如搶票,亦與秒殺類似,瞬時(shí)流量更甚。 一、為什么難 ????秒殺系統(tǒng)難做的原因:庫存只有一份,所有人會(huì)在集中的時(shí)間讀和寫這些數(shù)據(jù)。例如小米手機(jī)每周二的秒殺,可能手機(jī)只有1萬部,但瞬時(shí)進(jìn)入的流量可能是幾百幾千萬。又例如12306搶票,亦與秒殺類似,瞬時(shí)流量更甚。 主要需要解決的問題有兩個(gè): 高并發(fā)對(duì)數(shù)據(jù)庫...

    dinfer 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<