Spring Boot Redis分布式鎖:Lua腳本執行錯誤如何解決?

Spring Boot Redis分布式鎖:Lua腳本執行錯誤如何解決?

spring Boot集成redis實現分布式鎖:lua腳本錯誤排查與修復

使用spring bootredis構建分布式鎖時,若采用Lua腳本釋放鎖,可能會遇到執行錯誤。本文將剖析一個案例,分析錯誤根源并提供解決方案。

問題描述:

開發者嘗試使用Lua腳本釋放Redis分布式鎖,運行時報錯。核心代碼如下:

public void unlock(String key, Object value) {     String script = "if (redis.call('get',KEYS[1]) == ARGV[1]) then return redis.call('del',KEYS[1]) else return 0 end ";     DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script);     Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), value); }

這段代碼旨在通過Lua腳本檢查key是否存在且值與預期值匹配,若匹配則刪除key(釋放鎖),否則返回0。然而,單元測試報錯,錯誤信息包含org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is io.lettuce.core.RedisException: Java.lang.IllegalStateException。此外,redisTemplate.execute()方法的返回值類型與預期的Long類型不符,而是Object類型。

錯誤原因分析與解決方案:

錯誤主要源于兩方面:

  1. 參數類型不匹配: Collections.singletonList(key) 返回List,而Lua腳本的KEYS參數期望的是字符串數組。redisTemplate在處理此參數時可能存在類型轉換問題。更關鍵的是,value參數的類型與Lua腳本中ARGV[1]的預期類型不匹配,導致Lua腳本無法正確執行。使用StringRedisTemplate和ArrayList可以解決此問題。StringRedisTemplate確保參數類型的正確性,避免類型轉換錯誤;ArrayList則能精確傳遞Lua腳本所需的key數組。

  2. 返回值類型處理: 盡管redisScript的泛型指定為Long,但redisTemplate.execute()返回Object類型。這可能是底層Redis客戶端的返回值處理機制導致的。通過顯式設置redisScript.setResultType(Long.class),強制將返回值轉換為Long類型,避免類型轉換異常。

解決方案:

修改代碼如下:

stringRedisTemplate.opsForValue().set("a", "b"); String script = "if (redis.call('GET',KEYS[1]) == ARGV[1]) then return redis.call('DEL',KEYS[1]) else return 0 end "; DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script); redisScript.setResultType(Long.class); List<String> keys = new ArrayList<>(); keys.add("a"); Long result = stringRedisTemplate.execute(redisScript, keys, "b"); System.out.println(result);

通過使用StringRedisTemplate、ArrayList傳遞參數,并顯式設置setResultType,即可有效解決Lua腳本執行錯誤和返回值類型不匹配的問題。

? 版權聲明
THE END
喜歡就支持一下吧
點贊5 分享