基于Redis的SETNX实现分布式锁

原理

1

SET key value [NX] [XX] [EX <seconds>] [PX [millseconds]]

必选参数说明 

  • SET:命令

  • key:待设置的key

  • value: 设置的key的value

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

  • NX:表示key不存在才设置,如果存在则返回NULL

  • XX:表示key存在时才设置,如果不存在则返回NULL

  • EX seconds:设置过期时间,过期时间精确为秒

  • PX millseconds:设置过期时间,过期时间精确为毫秒

以上set 代替了 setnx + expire 需要分2次执行命令操作的方式,保证了原子性。

 

26d796c496edd7574e1f91c772f50757.png

 

如果setnx 返回ok 说明拿到了锁;如果setnx 返回 nil,说明拿锁失败,被其他线程占用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

<?php

/**

 * Created by phpStorm

 * Date: 2020/6/10/0010

 * Time: 17:38

 */

namespace common\helper;

use Yii;

 

class LockHelper

{

    private static $instance;

 

    private $redis;

 

    private function __construct()

    {

        if (!$this->redis instanceof Yii::$app->redis) {

            $this->redis = Yii::$app->redis;

        }

    }

 

    public static function instance()

    {

        if (!self::$instance || !self::$instance instanceof self) {

            self::$instance new static();

        }

        return self::$instance;

    }

 

    public static function getMicroTime()

    {

        $time = microtime();

        list($usec$sec) = explode(" "$time);

        return round(((float)$usec + (float)$sec) * 1000);

    }

 

    public function __call($func$params)

    {

        return call_user_func_array([$this->redis, $func], $params);

    }

 

    /*

     * 获取锁令牌 @todo 是否需要拼接特征码?

     */

    public static function getToken($preFix '')

    {

        $preFix = mt_rand(1111, 9999);

        $preFix $preFix . self::getMicroTime();

        return $preFix;

    }

 

    /*

     * 加锁

     * @params $ttl 过期时间(s)

     */

    public function setLock($key$token$ttl = 10)

    {

        if (!$keyreturn false;

        $redis $this->redis;

        $isLock $redis->set($key$token'NX''EX'$ttl);

        if ($isLock) {

            return true;

        }

        return false;

    }

 

 

    public function unLock($key$val)

    {

        if ($this->redis->get($key) == $val) {

            return $this->redis->del($key);

        }

        return false;

    }

 

    final private function __clone()

    {

        // TODO: Implement __clone() method.

    }

 

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值