-- 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