使用redis鎖的正確姿勢

2021-10-06 07:31:47 字數 4553 閱讀 2776

redis鎖的使用方式一般有三種,incr,setnx,set。

incr命令會將key的值加一,如果key值不存在,則key值會被初始化為0,然後執行incr操作。

127.0.0.1:6379> get lock_1234

(nil)

127.0.0.1:6379> incr lock_1234

(integer) 1

127.0.0.1:6379> get lock_1234

"1"

利用incr命令,結合程式構建鎖,具體使用邏輯如下:

1)建立程式中需要加鎖的key的關聯key值,可以在原key_name前加特定字元實現。如要加鎖的key_name為1234,則關聯key_name為lock_1234。

2)客戶端a執行incr lock_1234操作,如果為1,則無其他客戶端使用,先設定過期時間避免程式異常影響其他程式使用此key。如果值不為1,則有其他客戶端在占用此key,等一會再次訪問,直到值為0。

3)客戶端a處理完邏輯後刪除lock_1234。

具體**實現:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import redis

import time

rdb_host = '127.0.0.1'

rdb_port = 6379

rdb_pwd = 'root'

rdb_db = 13

db = redis.connectionpool(

host=rdb_host,

port=rdb_port,

password=rdb_pwd,

db=rdb_db)

rdb = redis.redis(connection_pool=db)

def redis_lock(order_id):

lock_key = 'lock_' + str(order_id)

incr = rdb.incr(lock_key)

if incr == 1:

rdb.expire(lock_key, 10)

print 'lock success'

rdb.delete(lock_key)

else:

print 'current key has been occupied'

time.sleep(1)

redis_lock(order_id)

if __name__ == '__main__':

redis_lock(1234)

setnx(set is not exists),當key不存在時可以為key設定值,返回1,否則返回0。

127.0.0.1:6379> get lock_2345

(nil)

127.0.0.1:6379> setnx lock_2345 lock

(integer) 1

127.0.0.1:6379> setnx lock_2345 lock

(integer) 0

127.0.0.1:6379> setnx lock_2345 abc

(integer) 0

利用setnx實現鎖操作和上邊的incr類似,具體實現如下:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import redis

import time

rdb_host = '127.0.0.1'

rdb_port = 6379

rdb_pwd = 'root'

rdb_db = 13

db = redis.connectionpool(

host=rdb_host,

port=rdb_port,

password=rdb_pwd,

db=rdb_db)

rdb = redis.redis(connection_pool=db)

def redis_lock_setnx(order_id):

lock_key = 'lock_' + str(order_id)

setnx = rdb.setnx(lock_key, 'lock')

if setnx == 1:

rdb.expire(lock_key, 10)

print 'lock success'

rdb.delete(lock_key)

else:

print 'current key has been occupied'

time.sleep(1)

redis_lock_setnx(order_id)

if __name__ == '__main__':

redis_lock_setnx(2345)

redis從2.6.12版本開始, set命令的行為可以通過一系列引數來修改。具體引數如下:

1)ex:設定鍵的過期時間為 second 秒。 

2)px:設定鍵的過期時間為 millisecond 毫秒。

3)nx:只在鍵不存在時,才對鍵進行設定操作。

4)xx:只在鍵已經存在時,才對鍵進行設定操作。

可以通過nx引數和ex引數實現鎖操作,**如下:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import redis

import time

rdb_host = '127.0.0.1'

rdb_port = 6379

rdb_pwd = 'root'

rdb_db = 13

db = redis.connectionpool(

host=rdb_host,

port=rdb_port,

password=rdb_pwd,

db=rdb_db)

rdb = redis.redis(connection_pool=db)

def redis_lock_set(order_id):

lock_key = 'lock_' + str(order_id)

set = rdb.set(lock_key, 'lock', ex=10, nx=true)

if set:

print 'lock success'

rdb.delete(lock_key)

else:

print 'current key has been occupied'

time.sleep(1)

redis_lock_set(order_id)

if __name__ == '__main__':

redis_lock_set(3456)

以上方式都設定了過期時間,原因在於如果程式由於某些bug以外退出了,不加過期時間的話,這個key會一直被鎖定,無法更新。

但是加過期時間來處理就會有問題,如果客戶端1在設定的過期時間內程式正常執行,但是沒有處理完,這時過期時間失效了,然後這個key的鎖被客戶端2獲取,在客戶端2還沒處理完的時候客戶端1處理完了,然後刪除了客戶端2的鎖。

針對這個問題可以在給鎖賦值的時候增加隨機字元,然後刪除的時候判斷下是否為自己賦的值就可以了。具體實現如下:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import redis

import time

rdb_host = '127.0.0.1'

rdb_port = 6379

rdb_pwd = 'root'

rdb_db = 13

db = redis.connectionpool(

host=rdb_host,

port=rdb_port,

password=rdb_pwd,

db=rdb_db)

rdb = redis.redis(connection_pool=db)

def redis_lock_set_random(order_id):

lock_key = 'lock_' + str(order_id)

lock_value = 'lock' + str(int(time.time()))

set = rdb.set(lock_key, lock_value, ex=10, nx=true)

if set:

print 'lock success'

if rdb.get(lock_key) == lock_value:

rdb.delete(lock_key)

else:

print 'current key has been occupied'

time.sleep(1)

redis_lock_set_random(order_id)

if __name__ == '__main__':

redis_lock_set_random(4567)

解鎖redis鎖的正確姿勢

redis是php的好朋友,在php寫業務過程中,有時候會使用到鎖的概念,同時只能有乙個人可以操作某個行為。這個時候我們就要用到鎖。鎖的方式有好幾種,php不能在記憶體中用鎖,不能使用zookeeper加鎖,使用資料庫做鎖又消耗比較大,這個時候我們一般會選用redis做鎖機制。鎖在redis中最簡單...

解鎖redis鎖的正確姿勢

redis是php的好朋友,在php寫業務過程中,有時候會使用到鎖的概念,同時只能有乙個人可以操作某個行為。這個時候我們就要用到鎖。鎖的方式有好幾種,php不能在記憶體中用鎖,不能使用zookeeper加鎖,使用資料庫做鎖又消耗比較大,這個時候我們一般會選用redis做鎖機制。鎖在redis中最簡單...

解鎖 redis 鎖的正確姿勢

redis 是 php 的好朋友,在 php 寫業務過程中,有時候會使用到鎖的概念,同時只能有乙個人可以操作某個行為。這個時候我們就要用到鎖。鎖的方式有好幾種,php 不能在記憶體中用鎖,不能使用 zookeeper 加鎖,使用資料庫做鎖又消耗比較大,這個時候我們一般會選用 redis 做鎖機制。鎖...