redis鎖的使用方式一般有三種,incr,setnx,set。
incr命令會將key的值加一,如果key值不存在,則key值會被初始化為0,然後執行incr操作。
利用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"
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。
具體**實現:
setnx(set is not exists),當key不存在時可以為key設定值,返回1,否則返回0。#!/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實現鎖操作和上邊的incr類似,具體實現如下: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
redis從2.6.12版本開始, set命令的行為可以通過一系列引數來修改。具體引數如下:#!/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)
1)ex:設定鍵的過期時間為 second 秒。
2)px:設定鍵的過期時間為 millisecond 毫秒。
3)nx:只在鍵不存在時,才對鍵進行設定操作。
4)xx:只在鍵已經存在時,才對鍵進行設定操作。
可以通過nx引數和ex引數實現鎖操作,**如下:
以上方式都設定了過期時間,原因在於如果程式由於某些bug以外退出了,不加過期時間的話,這個key會一直被鎖定,無法更新。#!/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)
但是加過期時間來處理就會有問題,如果客戶端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 做鎖機制。鎖...