日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Redis Lua脚本实现原子性操作

發布時間:2024/9/30 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis Lua脚本实现原子性操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、簡介

redis操作時單線程的,平常如果想要redis原子性操作的話,可以使用incrBy()和decrBy()方法進行原子性的加減,但是對于事務性的邏輯操作,沒有辦法實現原子性,Redis 使用單個 Lua 解釋器去運行所有腳本,當某個腳本正在運行的時候,不會有其他腳本或 Redis 命令被執行,因此,lua腳本需要運行的使用比較快,不會妨礙其它lua腳本執行

二、內容說明

redis命令

JedisClusterTemplate方法

作用

EVAL script numkeys key [key ...] arg [arg ...]eval()執行lua腳本
EVALSHA sha1 numkeys key [key ...] arg [arg ...]evalsha()執行lua腳本對應的緩存值
SCRIPT EXISTS script [script ...]scriptExists()判斷腳本是否已經添加到緩存中去了,1代表已經添加,0代表沒有添加
SCRIPT FLUSHscriptFlush()清除lua腳本緩存
SCRIPT KILLscriptKill()殺死當前正在運行的 Lua 腳本,當且僅當這個腳本沒有執行過任何寫操作時,這個命令才生效,防止lua腳本死循環
SCRIPT LOAD scriptscriptLoad()將腳本 script 添加到腳本緩存中,但并不立即執行這個腳本,eval是執行并添加緩存

1.eval命令

eval script numkeys key [key ...] arg [arg ...] #參數說明 #script:它會被運行在 Redis 服務器上下文中,這段腳本不必(也不應該)定義為一個 Lua 函數。 #numkeys:用于指定鍵名參數的個數。 #key:鍵名參數,表示在腳本中所用到的那些 Redis 鍵(key),這些鍵名參數可以在 Lua 中通過全局變量 KEYS 數組,用 1 為基址的形式訪問( KEYS[1] , KEYS[2] ,以此類推)。 #arg:全局變量,可以在 Lua 中通過全局變量 ARGV 數組訪問,訪問的形式和 KEYS 變量類似( ARGV[1] 、 ARGV[2] ,諸如此類)

使用樣例如下:執行腳本,,KEYS[1]對應foo,ARGV[1]對應第二個1,ARGV[2]對應100,角標[1]對應第1個參數,表示一個key,redis.call里面第一個參數redis命令,之后是該命令對應的key-value

--如果當前foo,對應的值減去1之后,小于0,那么就給它加上100返回,否則直接返回減去1值后的值 eval "if redis.call('decrBy',KEYS[1],ARGV[1]) < 0 thenreturn redis.call('incrBy',KEYS[1],ARGV[2]) elsereturn redis.call('get',KEYS[1]) end" 1 foo 1 100

執行結果如下:

?注意:腳本里使用的所有鍵都應該由 KEYS 數組來傳遞,變量入參通過ARGV數組傳遞

通過redis的eval命令來實現,使用 EVAL 命令對 Lua 腳本進行求值。在lua腳本中可以通過兩個不同的函數調用redis命令,分別是:redis.call()redis.pcall(),這兩者方法對于錯誤的處理方式不同

redis.call():redis.call關鍵字執行redis命令,在執行命令的過程中發生錯誤時,腳本會停止執行,并返回一個腳本錯誤,錯誤的輸出信息會說明錯誤造成的原因

redis.pcall(): 出錯時并不引發(raise)錯誤,而是返回一個帶 err 域的 Lua 表(table),用于表示錯誤

eval 命令會在每次執行腳本的時候都發送一次腳本主體(script body),每次都需要重新編譯腳本,會有一定的損耗

2.evalsha命令

evalsha命令和eval一樣,但它可以使用腳本生成的緩存sha來執行,出現錯誤是,會使用eval命令執行lua腳本?

#格式 evalsha sha1 numkeys key [key ...] arg [arg ...]

(1)Redis 保證所有被運行過的腳本都會被永久保存在腳本緩存當中,當 eval命令在一個 Redis 實例上成功執行某個腳本之后,隨后針對這個腳本的所有 evalsha命令都會成功執行,

(2)清空lua腳本方法需要使用 script flush命令

(3)不能使用全局性的腳本變量

3.其他命令

script load加載腳本到緩存中,但不立即執行,script exists判斷是否存在該緩存,script flush清除所有lua腳本緩存,script kill殺死正在執行中的命令

三、Java中使用Jedis操作

1.定義lua腳本

這里代表 key的value當前值減去ARGV[1],如果減去ARGV[1]之后小于0的話則返回原來值,否則返回減去之后的值

public static final String LUA = "if redis.call('decrBy',KEYS[1],ARGV[1]) < 0 then\n" +" return redis.call('incrBy',KEYS[1],ARGV[1])\n" +" else\n" +" return redis.call('get',KEYS[1])\n" +"end ";

2.加載lua腳本(可省略)

String key = "demo"; jedisClusterTemplate.set(key, "2"); log.info("加載腳本lua腳本:lua script={}", LUA); jedisClusterTemplate.scriptLoad(LUA, key);

3.使用eval執行lua腳本

執行jedisClusterTemplate中的eval方法,傳入lua腳本,key的個數,只有接入對應參數,參數對應前面2.1里面redis用法

總結

以上是生活随笔為你收集整理的Redis Lua脚本实现原子性操作的全部內容,希望文章能夠幫你解決所遇到的問題。

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