文章目錄
- 一.Lua腳本
- 1.Lua特性
- 2.Lua優勢
- 二.Lua語法
- 1.注釋
- 2.變量
- 3.數據類型:
- 3.1.基本類型
- 3.2.對象類型:表(table)
- 4.控制結構:
- 4.1.條件語句: 使用if、else和elseif來實現條件分支。
- 4.2.循環結構:Lua支持for循環、while循環和repeat...until循環。
- 5.函數
- 5.1.函數的定義與調用
- 5.2.匿名函數與閉包
- 6.模塊
- 1. 創建模塊
- 2.使用模塊
- 3.注意事項
- 6.字符串操作
- 7.錯誤處理
- 7.1.pcall
- 7.2.xpcall
- 7.3.自定義錯誤
- 8.創建線程和協程
- 9.如何使用lua標準庫
- 三.Lua腳本的應用場景
- 1. 緩存更新:
- 2. 原子操作:
- 3. 數據處理:
- 4. 分布式鎖:
- 四.Spring Boot中集成Lua腳本
- 1. 添加依賴
- 2.修改配置文件
- 3.創建Lua腳本
- 4.編寫Java代碼以加載和執行Lua腳本
- 4.1.直接運行內嵌在Java代碼中Lua腳本字符串
- 4.2.加載和運行Lua腳本文件
一.Lua腳本
Lua是一種輕量級、可嵌入的,自帶原子性
腳本語言,用標準C語言編寫并以源代碼形式開放, 其設計目的是為了嵌入應用程序中,從而為應用程序提供靈活的擴展和定制功能。廣泛應用于
游戲開發、Web開發和其他領域。``
1.Lua特性
- 輕量級: 它用標準C語言編寫并以源代碼形式開放,編譯后僅僅一百余K,可以很方便的嵌入別的程序里。
- 可擴展: Lua提供了非常易于使用的擴展接口和機制:由宿主語言(通常是C或C++)提供這些功能,Lua可以使用它們,就像是本來就內置的功能一樣。
- 數據類型豐富,包括
數字、字符串、布爾值、表(數組和字典的集合)等
。這些數據類型使得Lua語言能夠處理各種復雜的數據結構和算法。 - 支持面向過程(procedure-oriented)編程和函數式編程(functional programming);
- 自動內存管理;只提供了一種通用類型的表(table),用它可以實現數組,哈希表,集合,對象;
- 語言內置模式匹配;閉包(closure);函數也可以看做一個值;提供多線程(協同進程,并非操作系統所支持的線程)支持;
- 通過閉包和table可以很方便地支持面向對象編程所需要的一些關鍵機制,比如數據抽象,虛函數,繼承和重載等。
2.Lua優勢
Lua腳本在Redis中的使用有許多優勢,使其成為執行復雜操作的理想選擇。以下是一些主要原因:
性能
- Lua腳本在Redis中執行,避免了
多次的客戶端與服務器之間的通信
。這可以減少網絡開銷
,提高性能,特別是在需要執行多個Redis命令以完成一個操作時
。原子性:Redis保證Lua腳本的原子性執行,無需擔心競態條件或并發問題。
事務
Lua腳本可以與Redis事務一起使用
,確保一系列命令的原子性執行
。這允許你將多個操作視為一個單一的事務,要么全部成功,要么全部失敗
。
復雜操作
- Lua腳本提供了一種在Redis中執行復雜操作的方法,
允許你在一個腳本中組合多個Redis命令
。這對于處理復雜的業務邏輯非常有用,例計算和更新分布式計數器、實現自定義數據結構
等。
實現復雜的原子鎖
-
Lua腳本的執行是原子的,
這意味著在Lua腳本執行期間,沒有其他客戶端可以插入其他操作
。這使得Lua腳本在實現諸如分布式鎖、計數器、排行榜
等需要原子操作的情況下非常有用。 -
使用Lua腳本,你可以實現復雜的原子鎖,而不僅僅是使用Redis
的SETNX(set if not exists)
命令。這對于分布式鎖的實現非常重要。
減少網絡開銷
- 對于
大批量的數據處理
,Lua腳本可以減少客戶端和服務器之間的往返次數
,從而顯著減少網絡開銷。
減少服務器負載
通過將復雜的計算移至服務器端,可以減輕客戶端的負擔
,降低服務器的負載。
原生支持
Redis天生支持Lua腳本
,因此不需要額外的插件或擴展。
可讀性和維護性
- Lua腳本是一種常見的腳本語言,易于編寫和維護。將復雜邏輯封裝在腳本中有助于提高代碼的可讀性。
Lua腳本在Redis中的優勢在于它可以原子性地執行復雜操作、減少網絡通信、提高性能、減輕服務器負載,以及提高代碼的可讀性
。這使得它成為執行一系列復雜操作的理想選擇,尤其是在分布式系統
中需要高性能和可伸縮性的場景下。通過Lua腳本,Redis不僅成為一個鍵值存儲
,還能執行復雜的數據操作。
二.Lua語法
在線運行lua腳本網站https://www.bejson.com/runcode/lua/
1.注釋
注釋在Lua中用于添加說明和注解。單行注釋以–開始,多行注釋則使用–[[ … ]]。
-- 這是一條單行注釋--[[ 這是一個多行注釋可以跨越多行
]]
- 單行注釋:以
2個連續
的短橫線--
開始,直到該行結束 - 多行注釋:使用2個
方括號[[開始,并以2個方括號]]結束
2.變量
變量在Lua中無需顯式聲明類型。使用local關鍵字
創建局部變量,全局變量直接聲明。
local age = 30
name = "John" -- 全局變量
3.數據類型:
3.1.基本類型
基本數據類型包括整數、浮點數、字符串、布爾值和nil。
- 表tabile是一種非用
{}存儲鍵值對類型數據
,類似java的對象
-- 聲明不同類型的變量
local num = 42 -- 整數
local num2 = 3.14 -- 浮點數
local bool1 = true -- true
local bool2 = false -- false
local str1 = "Hello, World!" -- 雙引號字符串
local str2 = 'Lua is great!' -- 單引號字符串
3.2.對象類型:表(table)
表是Lua的核心數據結構,用花括號{}
定義。
-
表可以包含鍵值對,鍵和值可以是任何數據類型。
local person = { name = "John", age = 30, hobbies = {"Reading", "Gaming"} } print("姓名:" .. person.name) print("年齡:" .. person.age)
4.控制結構:
4.1.條件語句: 使用if、else和elseif來實現條件分支。
local age = 1
if age < 18 thenprint("未成年人")
elseif age >= 18 and age < 66 thenprint("成年人")
elseprint("老年人")
end
-- 未成年人
4.2.循環結構:Lua支持for循環、while循環和repeat…until循環。
for循環
for i = 1, 5 doprint(i)
end
while循環
local count = 0
while count < 3 doprint("循環次數: " .. count)count = count + 1
end
repeat…until循環
local count = 6
repeatprint("至少執行一次")
until count > 5
-- 至少執行一次
5.函數
函數在Lua中使用function+end關鍵字
定義,可以接收參數并返回值
。
function functionName(arg1, arg2, ...) -- 函數體 -- 這里是函數要執行的代碼 -- 可以使用參數arg1, arg2, ... return result -- (可選)返回結果
end
5.1.函數的定義與調用
-- 定義函數function add(a, b) local sum = a + b return sum end-- 調用add函數并打印結果 local result = add(3, 4) print("The sum is: " .. result) -- 輸出 "The sum is: 7"
5.2.匿名函數與閉包
-- 定義一個函數,它接受一個函數作為參數并調用它
function callFunction(func) func() -- 調用傳遞進來的匿名函數
end -- 創建一個匿名函數,并作為參數傳遞給callFunction
callFunction(function() print("Hello from an anonymous function!")
end) -- 輸出:
-- Hello from an anonymous function!
local outerVariable = "I'm outside!" -- 創建一個閉包
local function createClosure() return function() print(outerVariable) -- 訪問外部變量 end
end -- 獲取閉包并調用它
local closure = createClosure()
closure() -- 輸出:I'm outside!
6.模塊
Lua支持模塊化編程,允許將相關功能封裝在獨立的模塊中,并通過require關鍵字
加載它們。
1. 創建模塊
首先,我們創建一個名為myModule.lua
的模塊文件。在這個文件中,我們定義了一些函數和變量,并在文件末尾返回一個表,該表包含了模塊提供的所有公開功能和數據。
-- myModule.lua -- 私有變量
local privateVar = "This is a private variable" -- 私有函數
local function privateFunction() print("This is a private function")
end -- 公開函數
function myModule.publicFunction() print("This is a public function") print("Private variable is: " .. privateVar) -- 可以訪問私有變量
end -- 返回公開部分
return myModule
- 注意:在這個示例中,我們使用了myModule這個表來存儲公開的函數。這不是必須的,但這樣做可以使模塊的結構更清晰。
2.使用模塊
在另一個Lua腳本中,我們可以使用require函數來加載并使用
myModule模塊。
-- main.lua -- 加載模塊
local myModule = require("myModule") -- 調用模塊中的公開函數
myModule.publicFunction() -- 嘗試訪問模塊的私有部分(會失敗)
-- print(myModule.privateVar) -- 這將引發錯誤,因為privateVar是私有的
-- myModule.privateFunction() -- 這也會引發錯誤,因為privateFunction是私有的
3.注意事項
-
當使用require加載一個模塊時,Lua會首先檢查模塊是否已經被加載過。如果是,則直接返回之前加載的模塊,而不是重新加載。這有助于避免重復加載和初始化模塊。
-
模塊的路徑可以是
相對路徑或絕對路徑
。在上面的示例中,假設myModule.lua和main.lua
在同一目錄下,所以只使用了模塊名作為參數。如果模塊在其他位置,你需要提供正確的路徑
。 -
Lua的模塊系統相對簡單,沒有像一些其他語言那樣
復雜的包管理系統
。但是,你可以使用像LuaRocks這樣的第三方工具來管理和安裝Lua包
。
6.字符串操作
Lua提供了豐富的字符串操作功能,包括字符串連接、查找、替換、模式匹配
字符串連接
-
Lua中的字符串連接操作非常簡單,只需將兩個字符串相鄰放置即可。
local str1 = "Hello" local str2 = "World" local result = str1 .. str2 -- 連接字符串 print(result) -- 輸出:HelloWorld
字符串長度
-
使用#操作符可以獲取字符串的長度。
local str = "Hello" print(#str) -- 輸出:5
字符串查找
-
使用
string.find
函數可以在字符串中查找子串。該函數返回兩個值:子串開始的位置
和結束的位置
(如果不存在則返回nil)。local str = "Hello, World!" local start, end_ = string.find(str, "World") if start then print("Found 'World' at position", start) else print("Not found") end
字符串替換
-
使用
string.gsub函數
可以全局替換字符串中的子串。第一個參數是源字符串
,第二個參數是要被替換的模式
,第三個參數是替換成的字符串
,第四個參數(可選)是一個計數器,表示替換的最大次數。local str = "apple, apple, apple pie" local new_str = string.gsub(str, "apple", "orange") print(new_str) -- 輸出:orange, orange, orange pie -- 替換最多兩次 local new_str = string.gsub(str, "apple", "orange", 2) print(new_str) -- 輸出:orange, orange, apple pie
字符串切分
- 雖然Lua標準庫沒有直接提供字符串切分函數,但你可以使用
string.find和string.sub
組合來實現。或者,你可以使用第三方庫,如lua-string庫中的split函數
。function split(str, delim) local result = {} local from = 1 local delim_from, delim_to = string.find(str, delim, from) while delim_from do table.insert(result, string.sub(str, from, delim_from - 1)) from = delim_to + 1 delim_from, delim_to = string.find(str, delim, from) end table.insert(result, string.sub(str, from)) return result end local str = "apple,banana,cherry" local fruits = split(str, ",") for _, fruit in ipairs(fruits) do print(fruit) end -- 執行結果: -- apple -- banana -- cherry
字符串格式化
- Lua沒有內置的字符串格式化函數,但你可以使用
string.format函數
來模擬這個功能。local name = "Alice" local age = 30 local greeting = string.format("Hello, my name is %s and I'm %d years old.", name, age) print(greeting) -- 輸出:Hello, my name is Alice and I'm 30 years old.
字符串模式匹配
-
Lua提供了強大的模式匹配功能,通過
string.match、string.gmatch和string.find
等函數可以實現復雜的字符串處理。Lua的模式匹配基于一種類似于Perl的正則表達式語法。local str = "apple 123 orange 456" for number in string.gmatch(str, "%d+") do print(number) -- 輸出:123 和 456 end
7.錯誤處理
在Lua中,錯誤處理通常涉及到使用pcall(protected call)或xpcall(extended protected call)函數
來捕獲和處理可能出現的錯誤。當在Lua代碼中遇到錯誤時,它會拋出一個錯誤消息并終止當前的執行
。通過使用pcall或xpcall,你可以捕獲這些錯誤并繼續執行后續的代碼。
7.1.pcall
pcall函數接收一個函數
和一個可選的參數列表
,并嘗試以“保護”模式
調用該函數。
- 如果調用成功,pcal
l返回true以及函數的返回值
- 如果調用失敗(即拋出了錯誤),pcall
返回false以及錯誤消息
。
function riskyFunction() error("Something went wrong!")
end local status, result = pcall(riskyFunction)
if not status then print("An error occurred: " .. result)
else print("Function call was successful: " .. result)
end
-- An error occurred: script.lua:2: Something went wrong!
7.2.xpcall
xpcall與pcall類似,但它允許你提供一個錯誤處理函數
,該函數將在發生錯誤時被調用
。這使得你可以進行更復雜的錯誤處理。
function myErrorHandler(err) print("Caught an error: " .. err) -- 這里可以進行更復雜的錯誤處理 return debug.traceback(err, 2) -- 返回錯誤跟蹤信息
end function riskyFunction() error("Something went wrong!")
end local status, traceback = xpcall(riskyFunction, myErrorHandler)
if not status then print("An error occurred:") print(traceback)
end
執行結果
Caught an error: script.lua:8: Something went wrong!
An error occurred:
script.lua:8: Something went wrong!
stack traceback:[C]: in function 'error'script.lua:8: in function 'riskyFunction'[C]: in function 'xpcall'script.lua:11: in main chunk[C]: in ?
7.3.自定義錯誤
在Lua中,你可以使用error函數來拋出一個自定義的錯誤
。error函數接受一個字符串作為錯誤消息,并可以選擇性地提供一個錯誤級別。
function checkNumber(n) if type(n) ~= "number" then error("Not a number!", 2) -- 拋出一個錯誤 end print("The number is: " .. n)
end checkNumber("hello") -- 這將拋出一個錯誤
執行結果
/usr/local/lua-5.3.5/lua53: script.lua:8: Not a number!
stack traceback:[C]: in function 'error'script.lua:3: in function 'checkNumber'script.lua:8: in main chunk[C]: in ?
8.創建線程和協程
-- 創建協程
local cdata = coroutine.create(function () print("Hello from coroutine!") end) -- 定義函數
local function say_hello(name) print("Hello, " .. name) end
-- 調用函數,輸出 "Hello, Alice"
say_hello("Alice") -- 創建線程
local thread = coroutine.create(function () print("Hello from thread!") end)
-- 恢復線程,輸出 "Hello from thread!"
coroutine.resume(thread) -- Hello, Alice
-- Hello from thread!
9.如何使用lua標準庫
string庫:
- 提供了一系列用于處理字符串的函數,如查找、替換、連接、拆分、格式化等。
- 例如:string.find(), string.gsub(), string.format() 等。
table庫:
提供了一系列用于操作Lua表的函數,如表的插入、刪除、排序、遍歷等。
例如:table.insert(), table.remove(), table.sort(), table.concat() 等。
math庫:
- 提供了一系列數學函數,如三角函數、指數函數、對數函數、隨機數生成等。
- 例如:math.sin(), math.exp(), math.log(), math.random() 等。
io庫:
- 提供了文件操作的相關函數,用于讀寫文件、處理文件路徑等。
- 例如: io.open(), io.read(), io.write(), io.lines() 等。
os庫:
- 提供與操作系統相關的函數,如獲取當前時間、執行系統命令、處理環境變量等。
- 例如:os.time(), os.execute(), os.getenv(), os.setlocale() 等。
debug庫:
- 提供了一組用于調試的函數,如獲取堆棧跟蹤、設置和獲取斷點、操作局部變量等。
- 需要注意的是,debug庫中的一些功能在受限的環境中可能不可用或被禁用。
package庫:
- 提供了Lua模塊加載和搜索路徑管理的功能。
- 例如,你可以使用package.path和package.cpath來設置模塊的搜索路徑。
coroutine庫:
- 提供了協程(coroutine)管理的函數,允許你創建、恢復、讓出和銷毀協程。
- 協程是一種用戶態的輕量級線程,可以在Lua中實現非阻塞的I/O操作或并發編程。
怎么使用
- 在Lua中,
使用標準庫不需要使用關鍵字進行顯式引入(import)或加載(load
)。- Lua的標準庫是
預編譯并內置在Lua解釋器中的
,因此在你的Lua腳本中可以直接調用這些庫中的函數,而無需任何額外的步驟
。
- Lua的標準庫是
你只需要直接調用標準庫中的函數即可,例如:
三.Lua腳本的應用場景
1. 緩存更新:
場景:在緩存中存儲某些數據,但需要定期或基于條件更新
這些數據,同時確保在更新期間
不會發生并發問題
。
-
示例:使用Lua腳本,你可以
原子性地檢查數據的新鮮度
,如果需要更新,可以在一個原子性操作中重新計算數據并更新緩存
。-- 獲取鍵名,即從傳入腳本的參數列表KEYS中獲取第1個參數 local key = KEYS[1] -- 獲取緩存鍵 -- 根據key從緩存中獲取數據 local value = redis.call('GET', key ) -- 嘗試從緩存獲取數據-- 如果數據不存在(即data為nil) if not value then-- 數據不在緩存中,重新計算并設置--調用一個名為 calculateData 的函數(這個函數在腳本中沒有定義,但應該是一個用于重新計算數據的函數)value = calculateData()-- 將新計算的數據設置到緩存中 redis.call('SET', key , value ) end -- 返回數據(無論是從緩存中獲取的還是新計算的) return value
2. 原子操作:
Lua腳本的執行是原子的,這意味著在Lua腳本執行期間,沒有其他客戶端可以插入其他操作
。這使得Lua腳本在實現諸如分布式鎖、計數器、排行榜
等需要原子操作的情況下非常有用。
場景:需要執行多個Redis命令
作為一個原子操作,確保它們在多線程或多進程環境
下不會被中斷。
-
示例:使用Lua腳本,你可以將多個命令組合成一個原子操作,如
實現分布式鎖、計數器、排行榜
等。-- 獲取鍵名,即從傳入腳本的參數列表KEYS中獲取第1個參數 local key = KEYS[1] -- 獲取參數值,這是你想要設置的新值 ,即從傳入腳本的參數列表ARGV 中獲取第1個參數 local value = ARGV[1] -- 獲取當前鍵對應的值 local current = redis.call('GET', key) -- 如果當前值不存在(即current為nil),或者當前值(轉換為數字后)小于給定的參數值(也轉換為數字后) if not current or tonumber(current) < tonumber(value) then -- 如果當前值不存在或新值更大,設置新值redis.call('SET', key, value) end
3. 數據處理:
場景:需要對Redis中的數據進行復雜的處理,如統計、篩選、聚合等。
-
示例:使用Lua腳本,你可以在Redis中執行
復雜的數據處理
,而不必將數據傳輸到客戶端進行處理,減少網絡開銷。-- 從傳入腳本的參數列表中獲取第1個參數 local keyPattern = ARGV[1] -- 調用Redis的KEYS命令,根據給定的模式keyPattern獲取所有匹配的鍵。 -- 需要注意的是,KEYS命令在生產環境中應謹慎使用,因為它可能會阻塞Redis服務器,尤其是在有大量鍵存在時。 local keys = redis.call('KEYS', keyPattern) -- 初始化一個空的Lua表result,用于存儲處理后的數據 local result = {} --遍歷keys表中的每一個鍵 for i, key in ipairs(keys) do-- 獲取每個鍵對應的值 local data = redis.call('GET', key)-- 調用一個假設存在的processData函數處理這個值(注意:在腳本中并沒有給出processData函數的定義,你需要根據實際需求來實現它)。-- 然后處理后數據并添加到result表中table.insert(result, processData(data)) end --返回處理后的結果表。這個表包含了所有匹配鍵對應的處理后的數據。 return result
4. 分布式鎖:
場景:實現分布式系統中的鎖機制,確保只有一個客戶端
可以執行關鍵操作。
-
示例:使用Lua腳本,你可以
原子性地嘗試獲取鎖
,避免競態條件
,然后在完成后釋放鎖
。-- 獲取鎖的鍵名 local lockKey = KEYS[1] -- 獲取鎖的值,通常是一個唯一標識符(比如 UUID),用于在釋放鎖時驗證鎖的持有者。 local lockValue = ARGV[1] -- 獲取鎖的超時時間,單位是毫秒,如果在這個時間內鎖沒有被釋放(即 lockKey 沒有被刪除),則 Redis 會自動刪除這個鍵,避免死鎖。 local lockTimeout = ARGV[2]-- 嘗試使用 SET 命令來設置鎖,NX 表示只有在 key 不存在時設置值,PX 表示 key 的過期時間(毫秒) -- lockKey 不存在(NX),則設置其值為 lockValue,并設置其過期時間為 lockTimeout(PX)。如果設置成功,說明客戶端成功獲取到了鎖。 -- 如果 SET 命令執行成功,說明獲取到了鎖 if redis.call('SET', lockKey, lockValue, 'NX', 'PX', lockTimeout) then-- 鎖獲取成功,執行關鍵操作(這部分邏輯在腳本中沒有給出) -- ...-- 執行完關鍵操作后,刪除鎖鍵,釋放鎖 redis.call('DEL', lockKey) -- 釋放鎖-- 返回 true,表示成功獲取并釋放了鎖 return true else-- 鎖獲取失敗,可能是因為有其他客戶端已經持有了該鎖 return false
通常用于在分布式系統中確保多個客戶端在并發訪問共享資源時能夠正確地獲取和釋放鎖
,從而避免數據不一致的問題。
四.Spring Boot中集成Lua腳本
在Spring Boot中實現Lua腳本的執行主要涉及Spring Data Redis
和Lettuce(或Jedis)客戶端
的使用。
1. 添加依賴
添加Spring Data Redis和Lettuce(或Jedis)
的依賴。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>io.lettuce.core</groupId><artifactId>lettuce-core</artifactId>
</dependency>
2.修改配置文件
在application.properties或application.yml中配置Redis連接屬性,包括主機、端口、密碼等。
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=yourPassword
3.創建Lua腳本
創建一個Lua腳本,以執行你需要的操作。將腳本保存在Spring Boot項目
的合適位置。
-
假設有一個Lua腳本文件
myscript.lua
,它實現了一個簡單的計算:local a = tonumber(ARGV[1]) local b = tonumber(ARGV[2]) return a + b
4.編寫Java代碼以加載和執行Lua腳本
- 使用Spring Data Redis提供的
StringRedisTemplate
或LettuceConnectionFactory
4.1.直接運行內嵌在Java代碼中Lua腳本字符串
- 運行Lua腳本字符串:
@Service public class LuaScriptService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 運行Lua腳本字符串public Integer executeLuaScriptFromString() {// Lua腳本字符串,該腳本接收兩個參數(ARGV[1] 和 ARGV[2]),將它們轉換為數字并相加 String luaScript = "local a = tonumber(ARGV[1])\nlocal b = tonumber(ARGV[2])\nreturn a + b";// 創建一個Redis腳本對象,指定Lua腳本和期望的返回類型(Integer) RedisScript<Integer> script = new DefaultRedisScript<>(luaScript, Integer.class);// 創建一個空的keys數組,因為在這個Lua腳本中,我們不使用KEYS參數 String[] keys = new String[0]; // 通常情況下,沒有KEYS部分 // 創建一個args數組,包含兩個參數,這些參數將傳遞給Lua腳本 Object[] args = new Object[]{10, 20}; // 傳遞給Lua腳本的參數 // 使用stringRedisTemplate(它應該是已經配置好的Spring Data Redis的StringRedisTemplate實例) // 執行Lua腳本,并傳入keys和args數組 Integer result = stringRedisTemplate.execute(script, keys, args); // 返回執行Lua腳本后得到的結果(兩個數字的和) return result;} }
4.2.加載和運行Lua腳本文件
-
將Lua腳本保存到文件,例如
myscript.lua
。然后創建一個Java類來·加載和運行該腳本文件·:@Service public class LuaScriptService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate ResourceLoader resourceLoader;// 從文件中執行Lua腳本的方法 public Integer executeLuaScriptFromFile() {// 加載位于類路徑下的myscript.lua資源 Resource resource = resourceLoader.getResource("classpath:myscript.lua"); String luaScript; try { // 嘗試讀取資源文件內容,并將其轉換為字符串 luaScript = new String(resource.getInputStream().readAllBytes()); } catch (Exception e) { // 如果無法讀取Lua腳本文件,則拋出運行時異常 throw new RuntimeException("無法讀取Lua腳本文件。"); } // 創建一個Redis腳本對象,指定Lua腳本和期望的返回類型(Integer) RedisScript<Integer> script = new DefaultRedisScript<>(luaScript, Integer.class);// 創建一個空的keys數組,因為在這個Lua腳本中,我們不使用KEYS參數 String[] keys = new String[0]; // 通常情況下,沒有KEYS部分 // 創建一個args數組,包含兩個參數,這些參數將傳遞給Lua腳本 Object[] args = new Object[]{10, 20}; // 傳遞給Lua腳本的參數 // 使用stringRedisTemplate(它應該是已經配置好的Spring Data Redis的StringRedisTemplate實例) // 執行Lua腳本,并傳入keys和args數組 Integer result = stringRedisTemplate.execute(script, keys, args); // 返回執行Lua腳本后得到的結果(兩個數字的和) return result;} }
- 運行應用程序