php yii Redis实现并发锁

需要写一个抽奖活动,并发量很大,抽奖的同时需要操作多个数据表,决定采用redis锁.

网上找了一下,找到大牛的博客

http://www.cnblogs.com/yjf512/archive/2017/03/22/6597814.html

需要用到lua

Q:很好奇解锁的函数里为什么要用redis执行lua脚本,为什么不用php直接来操作呢?

A:群里问了下,大概明白了,redis是原子性,操作都是串行,但php是并发操作的,所以在高并发的时候可能存在脏读的问题,所以使用eval函数在redis里串行的执行这段代码,因为是串行的,不存在并发问题.

 

Q:如何实现阻塞锁

A:我没有在网上找到好的解决方案,都是自己写循环执行

 

SET key value [EX seconds] [PX milliseconds] [NX|XX]

将字符串值 value 关联到 key 。

如果 key 已经持有其他值, SET 就覆写旧值,无视类型。

对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。

可选参数

从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:

  • EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
  • PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX keymillisecond value 。
  • NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
  • XX :只在键已经存在时,才对键进行设置操作。

因为 SET 命令可以通过参数来实现和 SETNX 、 SETEX 和 PSETEX 三个命令的效果,所以将来的 Redis 版本可能会废弃并最终移除 SETNX 、 SETEX 和 PSETEX 这三个命令。

 

 1 <?php
 2 /**
 3  * Created by PhpStorm.
 4  * User: yiyz
 5  * Date: 2017/7/6
 6  * Time: 下午2:05
 7  */
 8 
 9 namespace common\vendor;
10 
11 
12 use common\helper\TextHelper;
13 
14 class RedisLock
15 {
16     private $key;
17     private $timeout;
18     private $token;
19 
20     public function __construct($key, $timeout = 10)
21     {
22         $this->key = $key;
23         $this->timeout = $timeout;
24         $this->token = TextHelper::generateOrderNo();
25     }
26 
27     /**
28      * 阻塞加锁
29      * @return bool
30      */
31     public function lock()
32     {
33         $timeStart = microtime(true) * 1000;
34         while (true) {
35             $res = \Yii::$app->redis->set($this->key, $this->token, "nx", "ex", $this->timeout);
36             if ($res) {
37                 break;
38             }
39             $timeEnd = microtime(true) * 1000;
40             if ($timeEnd - $timeStart > 10000) {
41                 //add log error
42                 return false;43             }
44         }
45         return true;
46     }
47 
48     /**
49      * 解锁
50      * @return mixed
51      */
52     public function unlock()
53     {
54         $script = '
55         if redis.call("get",KEYS[1]) == ARGV[1]
56         then
57             return redis.call("del",KEYS[1])
58         else
59             return 0
60         end';
61         return \Yii::$app->redis->eval($script, $this->key, $this->token);
62     }
63 }

随便写的,没经过测试,大牛不要笑我...

 

转载于:https://www.cnblogs.com/yiyz/p/7125991.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值