日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redis接口的二次封装

發(fā)布時間:2024/2/28 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis接口的二次封装 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

先看一下官方的調用示例代碼:

local redis = require "resty.redis" local red = redis:new()red:set_timeout(1000) -- 1 seclocal ok, err = red:connect("127.0.0.1", 6379) if not ok thenngx.say("failed to connect: ", err) return endok, err = red:set("dog", "an animal") if not ok thenngx.say("failed to set dog: ", err) return endngx.say("set result: ", ok)-- put it into the connection pool of size 100, -- with 10 seconds max idle time local ok, err = red:set_keepalive(10000, 100) if not ok thenngx.say("failed to set keepalive: ", err) return end

這是一個標準的redis接口調用,如果你的代碼中redis被調用頻率不高,那么這段代碼不會有任何問題。但如果你的項目重度依賴redis,工程中有大量的代碼在重復這樣一個動作,創(chuàng)建連接-->數據操作-->關閉連接(或放到連接池)這個完整的鏈路調用完畢,甚至還要考慮不同的return情況做不同處理,就很快發(fā)現代碼中有大量的重復。

Lua是不支持面向對象的。很多人用盡各種招術利用元表來模擬。可是,Lua的發(fā)明者似乎不想看到這樣的情形,因為他們把取長度的__len方法以及析構函數__gc留給了 C API。純 Lua 只能望洋興嘆。

我們期望的代碼應該是這樣的:

local red = redis:new() local ok, err = red:set("dog", "an animal") if not ok thenngx.say("failed to set dog: ", err) return endngx.say("set result: ", ok)local res, err = red:get("dog") if not res thenngx.say("failed to get dog: ", err) return endif res == ngx.null thenngx.say("dog not found.") return endngx.say("dog: ", res)

并且他自身具備以下幾個特征:

  • new、connect函數合體,使用時只負責申請,盡量少關心什么時候具體連接、釋放
  • 默認redis數據庫連接地址,但是允許自定義
  • 每次redis使用完畢,自動釋放redis連接到連接池供其他請求復用
  • 要支持redis的重要優(yōu)化手段 pipeline

不賣關子,只要干貨,我們最后是這樣干的,可以這里看到gist代碼

-- file name: resty/redis_iresty.lua local redis_c = require "resty.redis"local ok, new_tab = pcall(require, "table.new") if not ok or type(new_tab) ~= "function" thennew_tab = function (narr, nrec) return {} end endlocal _M = new_tab(0, 155) _M._VERSION = '0.01'local commands = {"append", "auth", "bgrewriteaof","bgsave", "bitcount", "bitop","blpop", "brpop","brpoplpush", "client", "config","dbsize","debug", "decr", "decrby","del", "discard", "dump","echo","eval", "exec", "exists","expire", "expireat", "flushall","flushdb", "get", "getbit","getrange", "getset", "hdel","hexists", "hget", "hgetall","hincrby", "hincrbyfloat", "hkeys","hlen","hmget", "hmset", "hscan","hset","hsetnx", "hvals", "incr","incrby", "incrbyfloat", "info","keys","lastsave", "lindex", "linsert","llen", "lpop", "lpush","lpushx", "lrange", "lrem","lset", "ltrim", "mget","migrate","monitor", "move", "mset","msetnx", "multi", "object","persist", "pexpire", "pexpireat","ping", "psetex", "psubscribe","pttl","publish", --[[ "punsubscribe", ]] "pubsub","quit","randomkey", "rename", "renamenx","restore","rpop", "rpoplpush", "rpush","rpushx", "sadd", "save","scan", "scard", "script","sdiff", "sdiffstore","select", "set", "setbit","setex", "setnx", "setrange","shutdown", "sinter", "sinterstore","sismember", "slaveof", "slowlog","smembers", "smove", "sort","spop", "srandmember", "srem","sscan","strlen", --[[ "subscribe", ]] "sunion","sunionstore", "sync", "time","ttl","type", --[[ "unsubscribe", ]] "unwatch","watch", "zadd", "zcard","zcount", "zincrby", "zinterstore","zrange", "zrangebyscore", "zrank","zrem", "zremrangebyrank", "zremrangebyscore","zrevrange", "zrevrangebyscore", "zrevrank","zscan","zscore", "zunionstore", "evalsha" }local mt = { __index = _M }local function is_redis_null( res )if type(res) == "table" thenfor k,v in pairs(res) doif v ~= ngx.null thenreturn falseendendreturn trueelseif res == ngx.null thenreturn trueelseif res == nil thenreturn trueendreturn false end-- change connect address as you need function _M.connect_mod( self, redis )redis:set_timeout(self.timeout)return redis:connect("127.0.0.1", 6379) endfunction _M.set_keepalive_mod( redis )-- put it into the connection pool of size 100, with 60 seconds max idle timereturn redis:set_keepalive(60000, 1000) endfunction _M.init_pipeline( self )self._reqs = {} endfunction _M.commit_pipeline( self )local reqs = self._reqsif nil == reqs or 0 == #reqs thenreturn {}, "no pipeline"elseself._reqs = nilendlocal redis, err = redis_c:new()if not redis thenreturn nil, errendlocal ok, err = self:connect_mod(redis)if not ok thenreturn {}, errendredis:init_pipeline()for _, vals in ipairs(reqs) dolocal fun = redis[vals[1]]table.remove(vals , 1)fun(redis, unpack(vals))endlocal results, err = redis:commit_pipeline()if not results or err thenreturn {}, errendif is_redis_null(results) thenresults = {}ngx.log(ngx.WARN, "is null")end-- table.remove (results , 1)self.set_keepalive_mod(redis)for i,value in ipairs(results) doif is_redis_null(value) thenresults[i] = nilendendreturn results, err endfunction _M.subscribe( self, channel )local redis, err = redis_c:new()if not redis thenreturn nil, errendlocal ok, err = self:connect_mod(redis)if not ok or err thenreturn nil, errendlocal res, err = redis:subscribe(channel)if not res thenreturn nil, errendres, err = redis:read_reply()if not res thenreturn nil, errendredis:unsubscribe(channel)self.set_keepalive_mod(redis)return res, err endlocal function do_command(self, cmd, ... )if self._reqs thentable.insert(self._reqs, {cmd, ...})returnendlocal redis, err = redis_c:new()if not redis thenreturn nil, errendlocal ok, err = self:connect_mod(redis)if not ok or err thenreturn nil, errendlocal fun = redis[cmd]local result, err = fun(redis, ...)if not result or err then-- ngx.log(ngx.ERR, "pipeline result:", result, " err:", err)return nil, errendif is_redis_null(result) thenresult = nilendself.set_keepalive_mod(redis)return result, err endfunction _M.new(self, opts)opts = opts or {}local timeout = (opts.timeout and opts.timeout * 1000) or 1000local db_index= opts.db_index or 0for i = 1, #commands dolocal cmd = commands[i]_M[cmd] =function (self, ...)return do_command(self, cmd, ...)endendreturn setmetatable({timeout = timeout,db_index = db_index,_reqs = nil }, mt) endreturn _M

調用示例代碼:

local redis = require "resty.redis_iresty" local red = redis:new()local ok, err = red:set("dog", "an animal") if not ok thenngx.say("failed to set dog: ", err) return endngx.say("set result: ", ok)

在最終的示例代碼中看到,所有的連接創(chuàng)建、銷毀連接、連接池部分,都被完美隱藏了,我們只需要業(yè)務就可以了。媽媽再也不用擔心我把redis搞垮了。

Todo list:目前resty.redis并沒有對redis 3.0的集群API做支持,既然統(tǒng)一了redis的入口、出口,那么對這個redis_iresty版本做適當調整完善,就可以支持redis 3.0的集群協議。由于我們目前還沒引入redis集群,這里也希望有使用的同學貢獻自己的補丁或文章。

總結

以上是生活随笔為你收集整理的redis接口的二次封装的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。