Redisson调evalSha抛异常:org.redisson.client.handler.CommandDecoder.decode

Redisson调evalSha抛异常:org.redisson.client.handler.CommandDecoder.decode,第1张

Lua脚本如下,key对应的值是个hash里面有type、userId、userName、ticket
,如果四个字段不存在或者四个字段完全相同,则表示加锁成功,否则视为加锁失败并且返回当前锁持有者的信息

--重要说明:
--参数type,userId,userName,ticket不能为空,需要在java代码中校验控制。
--返回结果res中code说明
--0、表示加锁失败。
--1、表示无人加锁并且参数ticket不为空,加锁成功,此举意味着如果key存在的话,后面从redis取到的值type、userId、ticket都不为空。
--2、表示同一type、同一用户、同一ticket,加锁成功,并且重新设置过期时间。
local hashTb=redis.call('hmget',KEYS[1],'type','userId','userName','ticket');
local exists=redis.call('exists',KEYS[1]);
local res={};
if exists==0
 then redis.call('hmset',KEYS[1],'type',ARGV[1],'userId',ARGV[2],'userName',ARGV[3],'ticket',ARGV[4]);
 redis.call('expire',KEYS[1],ARGV[5]);
 local ttl=redis.call('ttl',KEYS[1]);
 res={code='1',type=ARGV[1],userId=ARGV[2],userName=ARGV[3],ticket=ARGV[4],timeout=ttl};
elseif exists==1 and ARGV[1]==hashTb[1] and ARGV[2]==hashTb[2] and ARGV[4]==hashTb[4]
 then redis.call('expire',KEYS[1],ARGV[5]);
 local ttl=redis.call('ttl',KEYS[1]);
 res={code='2',type=hashTb[1],userId=hashTb[2],userName=hashTb[3],ticket=hashTb[4],timeout=ttl};
else
 local ttl=redis.call('ttl',KEYS[1]);
 local tb1=hashTb[1]==false and '' or hashTb[1];
 local tb2=hashTb[2]==false and '' or hashTb[2];
 local tb3=hashTb[3]==false and '' or hashTb[3];
 local tb4=hashTb[4]==false and '' or hashTb[4];
 res={code='0',type=tb1,userId=tb2,userName=tb3,ticket=tb4,timout=ttl};
end
 return cjson.encode(res);

控制台报错信息如下:

org.redisson.client.RedisException: ERR Error running script (call to f_711339d3f4791755f2d2302e82a31bc8976e0d17): @user_script:1: ERR value is not an integer or out of range . channel: [id: 0xbdf23c93, L:/10.4.36.15:1375 - R:test.bimdeco.com/139.196.144.93:31000] command: (EVALSHA), params: [711339d3f4791755f2d2302e82a31bc8976e0d17, 1, 01efc4f9-043c-4907-982a-1caf7c159df6, PooledUnsafeDirectByteBuf(ridx: 0, widx: 5, cap: 256), PooledUnsafeDirectByteBuf(ridx: 0, widx: 18, cap: 256), PooledUnsafeDirectByteBuf(ridx: 0, widx: 9, cap: 256), PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 256), PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 256)]
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:343)
	at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:178)
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:117)
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:102)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:505)
	at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283)

首先登上redis服务器查看到在key不存在的情况下,调用以后key已经存在,并且能看到里面对应的值,可以确定lua脚本调用成功了

但value非常奇怪,理论上应该如下所示:

怀疑是redis中lua脚本返回的结果(lua中处理成了json字符串),并不是按照redisson指定的序列化方式来序列化的。
经调试发现:
org.redisson.config.Config中默认的是用的
MarshallingCodec来序列化的

   public Config(Config oldConf) {
        setNettyHook(oldConf.getNettyHook());
        setExecutor(oldConf.getExecutor());

        if (oldConf.getCodec() == null) {
            // use it by default
            oldConf.setCodec(new MarshallingCodec());
        }

尝试改变redisson默认的序列化方式:
追踪了一下org.redisson.spring.starter.RedissonAutoConfiguration的源码发现
可以通过成员变量:private List redissonAutoConfigurationCustomizers来设置自己指定的序列化方式StringCodec
代码如下

@Bean
  public List<RedissonAutoConfigurationCustomizer> redissonAutoConfigurationCustomizers() {
    RedissonAutoConfigurationCustomizer customizer = configuration -> {
      StringCodec codec = new StringCodec();
      configuration.setCodec(codec);
    };
    List<RedissonAutoConfigurationCustomizer> list = new LinkedList<>();
    list.add(customizer);
    return list;
  }

然后重启服务后再次调用该接口,发现响应正常

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/719816.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存