業(yè)務站點中經(jīng)常需要對關系型數(shù)據(jù)庫的整形主鍵進行控制(不采用數(shù)據(jù)庫自動生成),
一般系統(tǒng)啟動后會讀取各業(yè)務表的最大主鍵扬虚,和業(yè)務表名形成一個字典(key為表名叠蝇,value為當前最大主鍵)翁潘,
當需要某業(yè)務表主鍵時從字典中進行查找并自動加一。
如果只有單個站點忍弛,主鍵信息的緩存都在本地沒有什么問題响迂,但要是站點進行了分布式部署,有多個備份细疚,
則多個備份多個緩存就會引起主鍵沖突蔗彤,這時就需要將生成主鍵的功能提取出來封裝成單獨的服務,
或者直接在Redis中實現(xiàn)自增疯兼。下面介紹的就是在Redis中實現(xiàn)主鍵自增的方式然遏。
注意:
1:Redis重啟后,腳本緩存消失镇防,生產(chǎn)環(huán)境需要在啟動redis時自動注冊腳本啦鸣。
2:這里沒有實現(xiàn)從關系型數(shù)據(jù)庫讀取所需數(shù)據(jù)表的最大主鍵的過程。
下文前提要熟悉lua的基本語法和概念来氧,需要一個python的環(huán)境并安裝redis庫诫给,當然也需要redis實例
啟動redis
python 環(huán)境和redis庫信息
redis自增值的lua腳本
local current_value = redis.call('GET', KEYS[1])
current_value = tonumber(current_value) or 0
local next_value = current_value + 1
redis.call('SET', KEYS[1], next_value)
return current_value
注意上述的 tonumber(current_value) or 0 語法
在 Redis Lua 腳本中,當使用數(shù)字類型之前沒有先將其初始化時啦扬,它們會默認為 nil中狂。
如果此后嘗試進行算術運算,就會出現(xiàn)lua redis attempt to perform arithmetic on a nil value錯誤扑毡。
需要確保在使用數(shù)字變量之前先將其初始化胃榕。可以使用 tonumber() 函數(shù)將字符串轉換為數(shù)字數(shù)據(jù)類型瞄摊,
并且如果值為 nil 則返回 0(或其他默認值)勋又。
采用 python 的Redis客戶端注冊 lua腳本到redis
Python文件 redis_nextkey.py
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
lua_script = """
local current_value = redis.call('GET', KEYS[1])
current_value = tonumber(current_value) or 0
local next_value = current_value + 1
redis.call('SET', KEYS[1], next_value)
return current_value
"""
sha = r.execute_command("SCRIPT", "LOAD", lua_script)
print(sha)
# 使用 register_script() 方法加載 Lua 腳本
#script = r.register_script(lua_script)
# 執(zhí)行腳本并輸出結果
#result = script('blz')
#print(result)
在 Python 的 Redis 模塊中苦掘,使用 register_script 方法注冊腳本時,并不會像 redis-cli 中那樣返回 SHA1 校驗和楔壤。
相反的鹤啡,該方法返回一個被封裝為 Script 類的對象,可以使用該對象來執(zhí)行已經(jīng)被 Redis 緩存的腳本蹲嚣。
像調用普通函數(shù)一樣調用該對象递瑰,并傳入 keys 和 args 參數(shù)。
在實際使用中隙畜,建議對這種方式進行封裝抖部,提高代碼復用性和可讀性。
Python 的 Redis 模塊允許使用 execute_command 方法向 Redis 服務器發(fā)送任何命令议惰,發(fā)送 SCRIPT LOAD 命令慎颗,則可以解析返回結果得到 SHA1
執(zhí)行Python腳本
根據(jù)返回的 SHA1 在redis-cil中測試
可見連續(xù)執(zhí)行時自動加一,如果是不存在的鍵則為0