Redis和Lua結(jié)合
1:redis.call:在腳本中調(diào)用Redis命令蚯嫌,遇到錯(cuò)誤會(huì)直接返回
2:redis.pcall:在腳本中調(diào)用Redis命令,遇到錯(cuò)誤會(huì)記錄錯(cuò)誤并繼續(xù)執(zhí)行
3:Lua數(shù)據(jù)類(lèi)型和Redis返回值類(lèi)型對(duì)應(yīng)
(1)數(shù)字——整數(shù)
(2)字符串——字符串
(3)表類(lèi)型——多行字符串
(4)表類(lèi)型(只有一個(gè)ok字段存儲(chǔ)狀態(tài)信息)——狀態(tài)回復(fù)
(5)表類(lèi)型(只有一個(gè)err字段存儲(chǔ)錯(cuò)誤信息)——錯(cuò)誤回復(fù)
4:eval命令:在Redis中執(zhí)行腳本
(1)格式是:eval 腳本內(nèi)容 key參數(shù)數(shù)量 [key…] [arg…]
(2)通過(guò)key和arg兩類(lèi)參數(shù)來(lái)向腳本傳遞數(shù)據(jù),在腳本中分別用KEYS和ARGV來(lái)獲取
注意:
對(duì)于KEYS和ARGV的使用并不是強(qiáng)制的晾浴,也可以不從KEYS去獲取鍵,而是在腳本中硬
編碼政己,比如:redis.call(‘get’,’user:’..ARGV[1]) 0 key1 愧薛,照樣能取到”user:key1”對(duì)應(yīng)的值晨炕。
但是這種寫(xiě)法,就無(wú)法兼容集群厚满,也就是說(shuō)不能在集群中使用府瞄。要兼容集群,建議
的方式是在客戶端獲取所有的key碘箍,然后通過(guò)KEYS傳到腳本中遵馆。
5:evalsha命令:可以通過(guò)腳本摘要來(lái)運(yùn)行,其他同eval丰榴。執(zhí)行的時(shí)候會(huì)根據(jù)摘要去找緩存的
腳本货邓,找到了就執(zhí)行,否則會(huì)返回錯(cuò)誤四濒。
6:script load:將腳本加入緩存换况,返回值就是SHA1摘要
7:script exists:判斷腳本是否已經(jīng)緩存
8:script flush:清空腳本緩存
9:script kill:強(qiáng)制終止腳本的執(zhí)行,如果腳本中修改了某些數(shù)據(jù)盗蟆,那么不會(huì)終止腳本的執(zhí)行戈二,以保證腳本執(zhí)行的原子性
沙箱
為了保證Redis服務(wù)器的安全,并且要確保腳本的執(zhí)行結(jié)果只和腳本執(zhí)行時(shí)傳遞的參數(shù)有關(guān)喳资,Redis禁止腳本中使用操作文件或系統(tǒng)調(diào)用相關(guān)的函數(shù)觉吭,腳本中只能對(duì)Redis數(shù)據(jù)進(jìn)行操作,這就是沙箱仆邓。
Redis會(huì)禁用腳本的全局變量鲜滩,以保證腳本之間是隔離的,互不相干的节值。
Redis對(duì)隨機(jī)數(shù)和隨機(jī)結(jié)果的處理
1:為了確保執(zhí)行結(jié)果可以重現(xiàn)徙硅,Redis對(duì)隨機(jī)數(shù)的功能進(jìn)行了處理,以保證每次執(zhí)行腳本生成的隨機(jī)數(shù)列都相同
2:Redis還對(duì)產(chǎn)生隨機(jī)結(jié)果進(jìn)行了處理搞疗,比如smembers或hkeys等嗓蘑,數(shù)據(jù)都是無(wú)序的,Redis會(huì)對(duì)結(jié)果按照字典進(jìn)行順序排序
3:對(duì)于會(huì)產(chǎn)生隨機(jī)結(jié)果但無(wú)法排序的命令匿乃,比如指揮產(chǎn)生一個(gè)元素脐往,Redis會(huì)在這類(lèi)命令執(zhí)行后,把該腳本標(biāo)記為lua_random_dirty扳埂,此后只允許調(diào)用讀命令,不許修改瘤礁,否則返回錯(cuò)誤阳懂,這類(lèi)Redis命令有:spop、srandmember、randomkey岩调、time巷燥。
MetaTable
用來(lái)實(shí)現(xiàn)重載操作符功能,基本示例如下:
1:自定義操作的函數(shù)号枕,示例:
myAdd={}
function myAdd.__add(f1,f2)
--具體的操作
end
2:為已有的table設(shè)置自定義的操作模板缰揪,示例:
setmetatable(tableA,myAdd)
setmetatable(tableB,myAdd)
3:對(duì)兩個(gè)table做加的操作,示例:
tableA+tableB 這個(gè)時(shí)候就會(huì)調(diào)用自定義的myAdd了葱淳,等于重載了默認(rèn)的_add方法钝腺,myAdd的__add方法就是MetaMethod
4:Lua內(nèi)建約定的MetaMethod :
__add(a, b) 、__sub(a, b)赞厕、__mul(a, b)艳狐、__div(a, b)、__mod(a, b)皿桑、__pow(a, b) 毫目、
__unm(a) 取反、__concat(a, b)诲侮、__len(a)镀虐、__eq(a, b)、__lt(a, b)沟绪、__le(a, b)刮便、__index(a, b)
對(duì)應(yīng)表達(dá)式 a.b、__newindex(a, b, c) 對(duì)應(yīng)表達(dá)式 a.b = c近零、__call(a, ...)
面向?qū)ο?/p>
Lua腳本的面向?qū)ο箢?lèi)似于JavaScript的面向?qū)ο笈岛耍际悄M的,比如:
1:直接創(chuàng)建對(duì)象:local user={userId='user1',userName='sishuok'}
2:添加新屬性:user.age = 12
3:添加方法
function user:show(a)
redis.log(redis.LOG_NOTICE,'a='..a..',age='..self['age'])
end
里面的self就相當(dāng)于this
4:就可以調(diào)用方法了:user:show('abc')
5:做個(gè)子類(lèi)來(lái)繼承user:
local child={address='bj'}
setmetatable(child,{__index=user})
__index在這里起的作用就類(lèi)似于JS中的Prototype
6:繼承了自然就可以調(diào)用父類(lèi)的屬性和方法了:child:show('child')
7:當(dāng)然你還可以定義自己的方法去覆蓋父類(lèi)的方法:
function child:show(a)
redis.log(redis.LOG_NOTICE,'child='..a..',age='..self['age']..',address=='..self.address)
end
模塊化
注意:這種方式不能在Redis中使用久信,目前不支持
1:可以直接使用require(“model_name”)來(lái)載入別的lua文件窖杀,文件的后綴是.lua。載入的時(shí)候就會(huì)直接執(zhí)行那個(gè)文件
2:載入同樣的lua文件時(shí)裙士,只有第一次的時(shí)候會(huì)去執(zhí)行入客,后面的相同的都不執(zhí)行了
3:如果要讓每一次文件都執(zhí)行,可使用dofile(“model_name”)函數(shù)
4:如果要載入后不執(zhí)行腿椎,等需要的時(shí)候執(zhí)行桌硫,可使用 loadfile(“model_name”)函數(shù),這種是把loadfile的結(jié)果賦值給一個(gè)變量啃炸,比如: