1. Environmental preparation
Dependency:Add Spring Data Redis to:
<dependency> <groupId></groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
Configure RedisTemplate:
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); (factory); (new StringRedisSerializer()); (new GenericJackson2JsonRedisSerializer()); return template; } }
2. Write Lua scripts
Taking distributed locks as an example, implement atomic operations of locking and unlocking:
Lock script
local key = KEYS[1] local value = ARGV[1] local expire = ARGV[2] -- ifkeyIf not, set,And add expiration time if ('setnx', key, value) == 1 then ('expire', key, expire) return 1 -- Locking successfully else return 0 -- Locking failed end
Unlock script
local key = KEYS[1] local value = ARGV[1] -- Only delete if the value of the lock matches if ('get', key) == value then return ('del', key) else return 0 end
3. Load and execute the script
Define script bean:
@Configuration public class LuaScriptConfig { @Bean public DefaultRedisScript<Long> lockScript() { DefaultRedisScript<Long> script = new DefaultRedisScript<>(); (new ClassPathResource("")); (); return script; } }
Calling script:
@Service public class RedisLockService { @Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private DefaultRedisScript<Long> lockScript; public boolean tryLock(String key, String value, int expireSec) { List<String> keys = (key); Long result = ( lockScript, keys, value, (expireSec) ); return result != null && result == 1; } }
Frequently Asked Questions and Solutions in Development
1. Lua script caching problem
- Problem: Each time the script is executed, the entire script content will be transmitted, increasing network overhead.
- Solution: Redis will automatically cache the script and return the SHA1 value, Spring Data Redis
DefaultRedisScript
SHA1 will be automatically managed. Make sure the script object is a singleton and avoid duplicate loading.
2. Parameter pass error
question:KEYS
andARGV
The number or type mismatch causes the script to fail to execute.
Solution: Clearly distinguish parameter types:
// Correct parameter transfer exampleList<String> keys = ("key1", "key2"); // KEYS arrayObject[] args = new Object[]{"arg1", "arg2"}; // ARGV array
3. Redis cluster compatibility
Problem: In cluster mode, the keys of all operations must be in the same slot.
Solution: Use{}
Define a hash tag and force the Key to be allocated to the same node:
String key = "{user}:lock:" + userId; // All keys containing {user} are allocated to the same node
4. Script performance issues
Problem: Complex Lua scripts may block Redis, affecting performance.
solve:
- Avoid using loops or complex logic in Lua.
- Preferred to using Redis built-in commands (e.g.
SETNX
、EXPIRE
)。
5. Exception handling
Problem: The script execution timed out or returned unexpected results.
Solution: Catch exceptions and design a retry mechanism:
public boolean tryLockWithRetry(String key, int maxRetry) { int retry = 0; while (retry < maxRetry) { if (tryLock(key, "value", 30)) { return true; } retry++; (100); // Wait for a short time } return false; }
Complete example: Distributed lock
// Add lockpublic boolean lock(String key, String value, int expireSec) { return ( lockScript, (key), value, (expireSec) ) == 1; } // Unlockpublic void unlock(String key, String value) { Long result = ( unlockScript, (key), value ); if (result == null || result == 0) { throw new RuntimeException("Unlock failed: Lock expired or non-holder"); } }
Debugging and optimization suggestions
Redis CLI debugging:
# Test scripts directly on Redis serverEVAL "return ('setnx', KEYS[1], ARGV[1])" 1 mykey 123
Log configuration:
# =DEBUG
Monitor script execution time:
# Redis slow query logslowlog-log-slower-than 5 slowlog-max-len 128
Summarize
Through Lua scripts, the atomicity of Redis complex operations can be easily achieved and the race condition problem under high concurrency can be solved. In Spring Boot, combineRedisTemplate
andDefaultRedisScript
, able to efficiently integrate Lua scripts. During development, you need to pay attention to parameter transmission, cluster compatibility and exception handling to avoid getting stuck.
This is the end of this article about using Lua scripts to implement Redis atomic operations. For more related contents of Lua scripts to implement Redis atomic operations, please search for my previous articles or continue browsing the following related articles. I hope everyone will support me in the future!