| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- -- redis_conn.lua
- local redis_conn = {}
- redis_conn.__index = redis_conn
- --[[
- 转义 Redis 参数,处理包含空格等特殊字符的值
- @param value 要转义的值
- @return 返回转义后的字符串
- ]]
- local function escape_value(value)
- if value == nil then
- return ""
- end
- -- 将值转换为字符串
- local str = tostring(value)
- -- 如果包含空格、引号或特殊字符,使用双引号包裹并转义内部引号
- if string.find(str, "[%s\"'\\]") then
- -- 转义反斜杠和双引号
- str = string.gsub(str, "\\", "\\\\")
- str = string.gsub(str, "\"", "\\\"")
- return "\"" .. str .. "\""
- end
- return str
- end
- --[[
- 还原 Redis 字符串(去转义)
- @param value 被转义的字符串
- @return 返回还原后的字符串
- ]]
- local function unescape_value(value)
- if value == nil then
- return nil
- end
- local str = tostring(value)
- -- 如果是用双引号包住的,去掉包裹并恢复转义
- if #str >= 2 and string.sub(str,1,1) == "\"" and string.sub(str,-1,-1) == "\"" then
- str = string.sub(str,2,-2)
- str = string.gsub(str, "\\\"", "\"")
- str = string.gsub(str, "\\\\", "\\")
- return str
- end
- return str
- end
- --[[
- 对数组进行去转义处理
- @param arr 数组
- @return 返回去转义后的数组
- ]]
- local function unescape_array(arr)
- if arr == nil or type(arr) ~= "table" then
- return arr
- end
- local result = {}
- for i, v in ipairs(arr) do
- result[i] = unescape_value(v)
- end
- return result
- end
- --[[
- 构建 Redis 命令字符串
- @param cmd 命令名称
- @param ... 命令参数
- @return 返回构建好的命令字符串
- ]]
- local function build_command(cmd, ...)
- local args = {...}
- local parts = {cmd}
- for i, arg in ipairs(args) do
- if arg ~= nil then
- table.insert(parts, escape_value(arg))
- end
- end
- return table.concat(parts, " ")
- end
- --[[
- 创建一个新的 fw_redis_conn 对象
- @return 返回一个新的 fw_redis_conn 对象
- ]]
- function redis_conn.new(__module)
- local instance = setmetatable({}, redis_conn)
- instance.module = __module
- return instance
- end
- --[[
- 关闭
- ]]
- function redis_conn:close()
- return self.module:close()
- end
- --[[
- 执行 Redis 命令
- @param cmd Redis 命令字符串
- @return 返回命令执行结果
- ]]
- function redis_conn:command(cmd)
- return self.module:command(cmd)
- end
- --[[
- 执行 Redis 命令
- @param args 命令参数数组,会自动将参数转换为字符串
- @return 返回命令执行结果
- ]]
- function redis_conn:command_ex(args)
- if args == nil or type(args) ~= "table" then
- return nil
- end
- local str_args = {}
- for i, arg in ipairs(args) do
- if arg == nil then
- table.insert(str_args, "")
- elseif type(arg) == "number" then
- -- 判断是否为整数:整数不转成小数
- if arg % 1 == 0 then
- -- 是整数,使用 %d 格式,避免转成小数
- table.insert(str_args, string.format("%d", arg))
- else
- -- 是浮点数,直接转字符串
- table.insert(str_args, tostring(arg))
- end
- else
- -- 其他类型(字符串、布尔等)直接转字符串
- table.insert(str_args, tostring(arg))
- end
- end
- return self.module:command_ex(str_args)
- end
- -- ==================== String 操作 ====================
- --[[
- GET 命令:获取键的值
- @param key 键名
- @return 返回键的值,不存在返回 nil
- ]]
- function redis_conn:get(key)
- local result = self:command(build_command("GET", key))
- return unescape_value(result)
- end
- --[[
- SET 命令:设置键值对
- @param key 键名
- @param value 值(可以是字符串、数字等,会自动处理空格)
- @param options 可选参数,如 "EX seconds" 或 "PX milliseconds" 或 "NX" 或 "XX"
- @return 返回执行结果
- ]]
- function redis_conn:set(key, value, options)
- local args = {"SET", key, value}
- if options then
- -- 如果 options 是字符串,需要拆分(如 "EX 10" 或 "NX")
- if type(options) == "string" then
- for word in string.gmatch(options, "%S+") do
- table.insert(args, word)
- end
- else
- table.insert(args, options)
- end
- end
- return self:command_ex(args)
- end
- --[[
- SETEX 命令:设置键值对并设置过期时间(秒)
- @param key 键名
- @param seconds 过期时间(秒)
- @param value 值
- @return 返回执行结果
- ]]
- function redis_conn:setex(key, seconds, value)
- return self:command_ex({"SETEX", key, seconds, value})
- end
- --[[
- SETNX 命令:当键不存在时设置键值对
- @param key 键名
- @param value 值
- @return 返回 1 表示设置成功,0 表示键已存在
- ]]
- function redis_conn:setnx(key, value)
- return self:command_ex({"SETNX", key, value})
- end
- --[[
- DEL 命令:删除一个或多个键
- @param ... 键名列表
- @return 返回删除的键数量
- ]]
- function redis_conn:del(...)
- local args = {"DEL", ...}
- return self:command_ex(args)
- end
- --[[
- EXISTS 命令:检查键是否存在
- @param key 键名
- @return 返回 1 表示存在,0 表示不存在
- ]]
- function redis_conn:exists(key)
- return self:command_ex({"EXISTS", key})
- end
- --[[
- KEYS 命令:查找所有匹配给定模式的键
- @param pattern 匹配模式,支持通配符:* 匹配任意字符,? 匹配单个字符,[] 匹配指定字符
- @return 返回匹配的键数组
- 注意:在生产环境中应谨慎使用,建议使用 SCAN 命令替代
- ]]
- function redis_conn:keys(pattern)
- local result = self:command_ex({"KEYS", pattern})
- return unescape_array(result)
- end
- --[[
- EXPIRE 命令:设置键的过期时间(秒)
- @param key 键名
- @param seconds 过期时间(秒)
- @return 返回 1 表示设置成功,0 表示键不存在或设置失败
- ]]
- function redis_conn:expire(key, seconds)
- return self:command_ex({"EXPIRE", key, seconds})
- end
- --[[
- TTL 命令:获取键的剩余过期时间(秒)
- @param key 键名
- @return 返回剩余秒数,-1 表示永不过期,-2 表示键不存在
- ]]
- function redis_conn:ttl(key)
- return self:command_ex({"TTL", key})
- end
- --[[
- INCR 命令:将键的值加 1
- @param key 键名
- @return 返回增加后的值
- ]]
- function redis_conn:incr(key)
- return self:command_ex({"INCR", key})
- end
- --[[
- DECR 命令:将键的值减 1
- @param key 键名
- @return 返回减少后的值
- ]]
- function redis_conn:decr(key)
- return self:command_ex({"DECR", key})
- end
- --[[
- INCRBY 命令:将键的值增加指定数值
- @param key 键名
- @param increment 增量
- @return 返回增加后的值
- ]]
- function redis_conn:incrby(key, increment)
- return self:command_ex({"INCRBY", key, increment})
- end
- --[[
- DECRBY 命令:将键的值减少指定数值
- @param key 键名
- @param decrement 减量
- @return 返回减少后的值
- ]]
- function redis_conn:decrby(key, decrement)
- return self:command_ex({"DECRBY", key, decrement})
- end
- -- ==================== Hash 操作 ====================
- --[[
- HGET 命令:获取哈希表中字段的值
- @param key 键名
- @param field 字段名
- @return 返回字段的值,不存在返回 nil
- ]]
- function redis_conn:hget(key, field)
- local result = self:command_ex({"HGET", key, field})
- return unescape_value(result)
- end
- --[[
- HSET 命令:设置哈希表中字段的值
- @param key 键名
- @param field 字段名
- @param value 值
- @return 返回 1 表示新建字段,0 表示更新字段
- ]]
- function redis_conn:hset(key, field, value)
- return self:command_ex({"HSET", key, field, value})
- end
- --[[
- HDEL 命令:删除哈希表中的一个或多个字段
- @param key 键名
- @param ... 字段名列表
- @return 返回删除的字段数量
- ]]
- function redis_conn:hdel(key, ...)
- local args = {"HDEL", key, ...}
- return self:command_ex(args)
- end
- --[[
- HEXISTS 命令:检查哈希表中字段是否存在
- @param key 键名
- @param field 字段名
- @return 返回 1 表示存在,0 表示不存在
- ]]
- function redis_conn:hexists(key, field)
- return self:command_ex({"HEXISTS", key, field})
- end
- --[[
- HGETALL 命令:获取哈希表中所有字段和值
- @param key 键名
- @return 返回字段和值的数组
- ]]
- function redis_conn:hgetall(key)
- local result = self:command_ex({"HGETALL", key})
- return unescape_array(result)
- end
- --[[
- HKEYS 命令:获取哈希表中所有字段名
- @param key 键名
- @return 返回字段名数组
- ]]
- function redis_conn:hkeys(key)
- local result = self:command_ex({"HKEYS", key})
- return unescape_array(result)
- end
- --[[
- HVALS 命令:获取哈希表中所有值
- @param key 键名
- @return 返回值数组
- ]]
- function redis_conn:hvals(key)
- local result = self:command_ex({"HVALS", key})
- return unescape_array(result)
- end
- --[[
- HLEN 命令:获取哈希表中字段数量
- @param key 键名
- @return 返回字段数量
- ]]
- function redis_conn:hlen(key)
- return self:command_ex({"HLEN", key})
- end
- -- ==================== List 操作 ====================
- --[[
- LPUSH 命令:从列表左端插入一个或多个值
- @param key 键名
- @param ... 值列表
- @return 返回插入后列表的长度
- ]]
- function redis_conn:lpush(key, ...)
- local args = {"LPUSH", key, ...}
- return self:command_ex(args)
- end
- --[[
- RPUSH 命令:从列表右端插入一个或多个值
- @param key 键名
- @param ... 值列表
- @return 返回插入后列表的长度
- ]]
- function redis_conn:rpush(key, ...)
- local args = {"RPUSH", key, ...}
- return self:command_ex(args)
- end
- --[[
- LPOP 命令:从列表左端弹出一个值
- @param key 键名
- @return 返回弹出的值,列表为空返回 nil
- ]]
- function redis_conn:lpop(key)
- local result = self:command_ex({"LPOP", key})
- return unescape_value(result)
- end
- --[[
- RPOP 命令:从列表右端弹出一个值
- @param key 键名
- @return 返回弹出的值,列表为空返回 nil
- ]]
- function redis_conn:rpop(key)
- local result = self:command_ex({"RPOP", key})
- return unescape_value(result)
- end
- --[[
- LLEN 命令:获取列表长度
- @param key 键名
- @return 返回列表长度
- ]]
- function redis_conn:llen(key)
- return self:command_ex({"LLEN", key})
- end
- --[[
- LRANGE 命令:获取列表指定范围内的元素
- @param key 键名
- @param start 起始索引(从 0 开始)
- @param stop 结束索引(-1 表示最后一个元素)
- @return 返回元素数组
- ]]
- function redis_conn:lrange(key, start, stop)
- local result = self:command_ex({"LRANGE", key, start, stop})
- return unescape_array(result)
- end
- -- ==================== Set 操作 ====================
- --[[
- SADD 命令:向集合添加一个或多个成员
- @param key 键名
- @param ... 成员列表
- @return 返回添加的成员数量
- ]]
- function redis_conn:sadd(key, ...)
- local args = {"SADD", key, ...}
- return self:command_ex(args)
- end
- --[[
- SREM 命令:从集合移除一个或多个成员
- @param key 键名
- @param ... 成员列表
- @return 返回移除的成员数量
- ]]
- function redis_conn:srem(key, ...)
- local args = {"SREM", key, ...}
- return self:command_ex(args)
- end
- --[[
- SMEMBERS 命令:获取集合所有成员
- @param key 键名
- @return 返回成员数组
- ]]
- function redis_conn:smembers(key)
- local result = self:command_ex({"SMEMBERS", key})
- return unescape_array(result)
- end
- --[[
- SISMEMBER 命令:检查成员是否在集合中
- @param key 键名
- @param member 成员
- @return 返回 1 表示存在,0 表示不存在
- ]]
- function redis_conn:sismember(key, member)
- return self:command_ex({"SISMEMBER", key, member})
- end
- --[[
- SCARD 命令:获取集合成员数量
- @param key 键名
- @return 返回成员数量
- ]]
- function redis_conn:scard(key)
- return self:command_ex({"SCARD", key})
- end
- -- ==================== Sorted Set 操作 ====================
- --[[
- ZADD 命令:向有序集合添加一个或多个成员
- @param key 键名
- @param score 分数
- @param member 成员
- @param ... 可选的更多 score-member 对
- @return 返回添加的成员数量
- ]]
- function redis_conn:zadd(key, score, member, ...)
- local args = {"ZADD", key, score, member, ...}
- return self:command_ex(args)
- end
- --[[
- ZRANGE 命令:获取有序集合指定范围内的成员
- @param key 键名
- @param start 起始索引
- @param stop 结束索引
- @param withscores 是否包含分数,默认为 false
- @return 返回成员数组(如果 withscores 为 true,则包含分数)
- ]]
- function redis_conn:zrange(key, start, stop, withscores)
- local args = {"ZRANGE", key, start, stop}
- if withscores then
- table.insert(args, "WITHSCORES")
- end
- local result = self:command_ex(args)
- if result == nil or type(result) ~= "table" then
- return result
- end
- -- 如果 withscores 为 true,结果是 [member1, score1, member2, score2, ...]
- -- 只处理成员部分(奇数索引),分数部分保持不变
- if withscores then
- local unescaped = {}
- for i = 1, #result do
- if i % 2 == 1 then
- -- 成员(奇数索引)
- unescaped[i] = unescape_value(result[i])
- else
- -- 分数(偶数索引)
- unescaped[i] = result[i]
- end
- end
- return unescaped
- else
- return unescape_array(result)
- end
- end
- --[[
- ZREM 命令:从有序集合移除一个或多个成员
- @param key 键名
- @param ... 成员列表
- @return 返回移除的成员数量
- ]]
- function redis_conn:zrem(key, ...)
- local args = {"ZREM", key, ...}
- return self:command_ex(args)
- end
- --[[
- ZCARD 命令:获取有序集合成员数量
- @param key 键名
- @return 返回成员数量
- ]]
- function redis_conn:zcard(key)
- return self:command_ex({"ZCARD", key})
- end
- --[[
- ZSCORE 命令:获取有序集合成员的分数
- @param key 键名
- @param member 成员
- @return 返回分数,成员不存在返回 nil
- ]]
- function redis_conn:zscore(key, member)
- local result = self:command_ex({"ZSCORE", key, member})
- -- 分数通常是数字,但为了统一处理,也进行去转义
- if result ~= nil then
- return unescape_value(result)
- end
- return result
- end
- return redis_conn
|