Redisson lua
Redis支持使用lua脚本来执行原子操作,Redisson中也提供了RScript接口,用于执行lua脚本,并提供了实现类RedissonScript。
1. API举例:
RedissonScript.eval(Mode mode, String luaScript, ReturnType returnType, List keys, Object… values); 在lua脚本中可以用KEYS、ARGV数组(两个数组下标均从1开始)来接收keys和values,需要注意的是value会进行序列化(并不是RScript的ARGV如此,redisson在存储时,都会对value进行序列化)。
2. redisson序列化特性
假设有一个hash结构,key是room,field是roomId,value是Long型的{roomId}。那么通过redisson API写入可以观察到redis中的field和value结构分别如下图所示:
特别强调的是,图中的首尾的双引号字符以及反斜杠,在实际的field和value中并不存在,这只是通过redis cli查询时显示效果。
实际上redis中的field是:
"roomId"
value是:
["java.lang.Long",123456]
中括号[]中两个值分别表示value的类型和取值。
3. 脚本示例
示例1:(1)在lua中使用KEYS和ARGV数组,(2)在lua中构造序列化的value
- redisson只有key没有做序列化,各种数据结构中field、value都进行了序列化。
如下代码展示了使用lua脚本写和读hash结构。key是roomId,field是roomId(实际存储的是”roomId”),value是123456(实际存储的是[”java.lang.Long”,123456])。
@Test
public void testLuaScript() {
RedissonClient redissonClient = redissonService.redissonClient();
RScript rScript = redissonClient.getScript();
Long roomId = 123456L;
String hsetRoomId = "redis.call('HSET', KEYS[1], ARGV[1], ARGV[2]);" +
"return redis.call('HGET', KEYS[1], '\"roomId\"');";
Long result = rScript.eval(RScript.Mode.READ_WRITE, hsetRoomId, RScript.ReturnType.INTEGER,
Lists.newArrayList("room"),
Lists.newArrayList("roomId", roomId).toArray());
Assert.assertTrue(roomId.equals(result));
}
第一行lua脚本,使用ARGV[1]作为field进行写入,第二行使用lua字符串作为field进行读取,结果验证了lua会在存储时进行序列化特性。
- 需要注意的是第二行lua脚本多写了反斜杠是为了转义。
示例2:在lua中处理获得的value
lua脚本中获取到序列化的value,并进行处理。 由于我不擅长lua脚本,也不清楚在redisson中 lua是否可以使用一些json库,所以简单的使用lua的字符串API进行处理。处理代码示例:
local roomId = string.sub(roomIdJson, string.find(roomIdJson, ',') + 1, string.len(roomIdJson) - 1);
测试代码:
@Test
public void testLuaScript2() {
Long roomId = 123456L;
// 准备数据结构:(1)存储roomId,key为room, field为roomId, value为123456
// (2)存储123456房间中用户列表,key为roomId.123456, value为字符串数组对象
redisService.hsetWithThrow("room", "roomId", roomId, true);
redisService.setWithThrow("roomId.123456", Lists.newArrayList("Jack", "Rose"));
RedissonClient redissonClient = redissonService.redissonClient();
RScript rScript = redissonClient.getScript();
String getRoomUserList =
// roomIdJson = ["java.lang.Long",123456]
"local roomIdJson = redis.call('HGET', KEYS[1], '\"roomId\"'); " +
"local roomId = " +
" string.sub(roomIdJson, string.find(roomIdJson, ',') + 1, string.len(roomIdJson) - 1); " +
"return redis.call('GET', 'roomId' .. '.' .. roomId); ";
ArrayList result = rScript.eval(RScript.Mode.READ_WRITE, getRoomUserList, RScript.ReturnType.VALUE,
Lists.newArrayList("room"),
new Object[0]);
Assert.assertTrue(result.contains("Jack"));
}