Redis 中的自增值
业务站点中经常需要对关系型数据库的整形主键进行控制(不采用数据库自动生成),
一般系统启动后会读取各业务表的最大主键,和业务表名形成一个字典(key为表名,value为当前最大主键),
当需要某业务表主键时从字典中进行查找并自动加一。
如果只有单个站点,主键信息的缓存都在本地没有什么问题,但要是站点进行了分布式部署,有多个备份,
则多个备份多个缓存就会引起主键冲突,这时就需要将生成主键的功能提取出来封装成单独的服务,
或者直接在Redis中实现自增。下面介绍的就是在Redis中实现主键自增的方式。
注意:
1:Redis重启后,脚本缓存消失,生产环境需要在启动redis时自动注册脚本。
2:这里没有实现从关系型数据库读取所需数据表的最大主键的过程。
下文前提要熟悉lua的基本语法和概念,需要一个python的环境并安装redis库,当然也需要redis实例
启动redis
image.pngpython 环境和redis库信息
image.pngredis自增值的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 脚本中,当使用数字类型之前没有先将其初始化时,它们会默认为 nil。
如果此后尝试进行算术运算,就会出现lua redis attempt to perform arithmetic on a nil value错误。
需要确保在使用数字变量之前先将其初始化。可以使用 tonumber() 函数将字符串转换为数字数据类型,
并且如果值为 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)
# 执行脚本并输出结果
#result = script('blz')
#print(result)
在 Python 的 Redis 模块中,使用 register_script 方法注册脚本时,并不会像 redis-cli 中那样返回 SHA1 校验和。
相反的,该方法返回一个被封装为 Script 类的对象,可以使用该对象来执行已经被 Redis 缓存的脚本。
像调用普通函数一样调用该对象,并传入 keys 和 args 参数。
在实际使用中,建议对这种方式进行封装,提高代码复用性和可读性。
Python 的 Redis 模块允许使用 execute_command 方法向 Redis 服务器发送任何命令,发送 SCRIPT LOAD 命令,则可以解析返回结果得到 SHA1
执行Python脚本
image.png根据返回的 SHA1 在redis-cil中测试
image.png可见连续执行时自动加一,如果是不存在的键则为0