当前位置:Gxlcms > PHP教程 > 如何利用Redis锁解决高并发问题

如何利用Redis锁解决高并发问题

时间:2021-07-01 10:21:17 帮助过:18人阅读

高并发问题是我们经常可以遇到的问题,那么该如何解决高并发这个问题呢?本篇文章介绍的内容就是利用Redis锁解决高并发问题,一起来看看吧。

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

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

创建库存表

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

设置初始库存为10

创建订单表

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

测试不用锁的时候

  1. $pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
  2. $sql="select `number` from storage where id=1 limit 1";
  3. $res = $pdo->query($sql)->fetch();
  4. $number = $res['number'];
  5. if($number>0)
  6. {
  7. $sql ="insert into `order` VALUES (null,$number)";
  8. $order_id = $pdo->query($sql);
  9. if($order_id)
  10. {
  11. $sql="update storage set `number`=`number`-1 WHERE id=1";
  12. $pdo->query($sql);
  13. }
  14. }

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

  1. mysql> select * from storage;
  2. +----+--------+
  3. | id | number |
  4. +----+--------+
  5. | 1 | 0 |
  6. +----+--------+
  7. 1 row in set (0.00 sec)

在来看订单表

  1. mysql> select * from `order`;
  2. +----+--------+
  3. | id | number |
  4. +----+--------+
  5. | 1 | 10 |
  6. | 2 | 10 |
  7. | 3 | 9 |
  8. | 4 | 7 |
  9. | 5 | 6 |
  10. | 6 | 5 |
  11. | 7 | 5 |
  12. | 8 | 5 |
  13. | 9 | 4 |
  14. | 10 | 1 |
  15. +----+--------+
  16. 10 rows in set (0.00 sec)

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

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

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: daisc
  5. * Date: 2018/7/23
  6. * Time: 14:45
  7. */
  8. class Lock
  9. {
  10. private static $_instance ;
  11. private $_redis;
  12. private function __construct()
  13. {
  14. $this->_redis = new Redis();
  15. $this->_redis ->connect('127.0.0.1');
  16. }
  17. public static function getInstance()
  18. {
  19. if(self::$_instance instanceof self)
  20. {
  21. return self::$_instance;
  22. }
  23. return self::$_instance = new self();
  24. }
  25. /**
  26. * @function 加锁
  27. * @param $key 锁名称
  28. * @param $expTime 过期时间
  29. */
  30. public function set($key,$expTime)
  31. {
  32. //初步加锁
  33. $isLock = $this->_redis->setnx($key,time()+$expTime);
  34. if($isLock)
  35. {
  36. return true;
  37. }
  38. else
  39. {
  40. //加锁失败的情况下。判断锁是否已经存在,如果锁存在切已经过期,那么删除锁。进行重新加锁
  41. $val = $this->_redis->get($key);
  42. if($val&&$val<time())
  43. {
  44. $this->del($key);
  45. }
  46. return $this->_redis->setnx($key,time()+$expTime);
  47. }
  48. }
  49. /**
  50. * @param $key 解锁
  51. */
  52. public function del($key)
  53. {
  54. $this->_redis->del($key);
  55. }
  56. }
  57. $pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
  58. $lockObj = Lock::getInstance();
  59. //判断是能加锁成功
  60. if($lock = $lockObj->set('storage',10))
  61. {
  62. $sql="select `number` from storage where id=1 limit 1";
  63. $res = $pdo->query($sql)->fetch();
  64. $number = $res['number'];
  65. if($number>0)
  66. {
  67. $sql ="insert into `order` VALUES (null,$number)";
  68. $order_id = $pdo->query($sql);
  69. if($order_id)
  70. {
  71. $sql="update storage set `number`=`number`-1 WHERE id=1";
  72. $pdo->query($sql);
  73. }
  74. }
  75. //解锁
  76. $lockObj->del('storage');
  77. }
  78. else
  79. {
  80. //加锁不成功执行其他操作。
  81. }

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

  1. mysql> select * from `order`;
  2. +----+--------+
  3. | id | number |
  4. +----+--------+
  5. | 1 | 10 |
  6. | 2 | 9 |
  7. | 3 | 8 |
  8. | 4 | 7 |
  9. | 5 | 6 |
  10. | 6 | 5 |
  11. | 7 | 4 |
  12. | 8 | 3 |
  13. | 9 | 2 |
  14. | 10 | 1 |
  15. +----+--------+
  16. 10 rows in set (0.00 sec)

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

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

相关推荐:

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

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

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

人气教程排行