最近在学习黑马程序员的黑马点评项目中,使用到Lua脚本来确保程序的原子性。下面是对该Lua脚本使用的总结
Lua脚本内容:
以下是输出锁的脚本内容
1 2 3 4 5 6 7 8
|
if(redis.call('get',KEY[1])==ARGV[1]) then
return redis.call('del',KEY[1]) end
return 0
|
Lua脚本的加载:
1 2 3 4 5 6
| private static final DefaultRedisScript<Long> UNLOCK_SCRIPT; static { UNLOCK_SCRIPT = new DefaultRedisScript<>(); UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua")); UNLOCK_SCRIPT.setResultType(Long.class); }
|
1. 静态变量声明
1
| private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
|
- 作用:声明一个静态不可变的
DefaultRedisScript对象,泛型<Long>表示脚本返回值的类型为Long。
- 设计意图:
static final:确保全局唯一实例,避免重复创建对象。
- 泛型
Long:明确Lua脚本执行结果的类型,避免运行时类型转换错误。
2. 静态初始化块
- 执行时机:在类加载时执行,且仅执行一次。
- 适用场景:适合初始化静态资源(如配置文件、脚本等),避免重复加载的开销。
3. 创建DefaultRedisScript实例
1
| UNLOCK_SCRIPT = new DefaultRedisScript<>();
|
- 对象功能:封装Lua脚本的元数据,包括脚本内容、SHA1哈希值和结果类型。
- 底层机制:
- 实现
RedisScript接口,适配Spring的RedisTemplate执行逻辑。
- 内部缓存脚本的SHA1哈希值,优先使用
EVALSHA命令执行,减少网络传输。
4. 设置脚本路径
1
| UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
|
- 参数解析:
ClassPathResource:Spring提供的资源加载器,从类路径(如resources/目录)读取文件。
unlock.lua:Lua脚本文件名,需与实际文件路径一致。
- 加载过程:
- 读取
unlock.lua文件内容。
- 计算脚本内容的SHA1哈希值(如
a1b2c3d4...)。
- 将脚本和哈希值缓存到
DefaultRedisScript对象中。
5. 设置结果类型
1
| UNLOCK_SCRIPT.setResultType(Long.class);
|
- 必要性:明确Redis返回值的Java类型,避免反序列化异常。
- 匹配规则:
- Lua返回整数(如
1或0) → 映射为Long类型。
- Lua返回
nil → 映射为null。
- Lua返回布尔值 → 需设置为
Boolean.class。
Lua脚本的调用
1 2 3 4 5 6 7 8 9
| @Override public void unlock() {
stringRedisTemplate.execute( UNLOCK_SCRIPT, Collections.singletonList(KEY_PREFIX + name), ID_PREFIX+Thread.currentThread().getId() ); }
|
execute()方法接受三个参数,第一个script,要执行的脚本;第二个需要传递给脚本的任何键,第三个,需要传递给脚本的任何args。