redisson类RMapCache执行addAndGet报错问题解决

本文介绍了在使用Redisson的RMapCache类执行addAndGet操作时遇到的问题,通过分析错误并提供正确的代码示例,帮助读者理解和解决这类报错,确保缓存操作的正确执行。

报错

ERR Error running script (call to f_xxx): 
@user_script:1: user_script:1: attempt to perform arithmetic on a nil value . 
channel: [id: xxx, L:/xxx - R:/xxx] 
command: (EVAL), params: [local value = redis.call('hget', KEYS[1], ARGV[2]); 
local expireDate = 92233720368547758; local t = ..., 8, xxx:xxx:pv, 
redisson__timeout__set:{xxx:xxx:pv}, redisson__idle__set:{xxx:xxx:pv}, 
redisson_map_cache_created:{xxx:xxx:pv}, redisson_map_cache_updated:{xxx:xxx:pv}, 
redisson__map_cache__last_access__set:{xxx:xxx:pv}, 
redisson_map_cache_removed:{xxx:xxx:pv}, {xxx:xxx:pv}:redisson_options, ...]

代码

RMapCache<String, Integer> mapCache = redissonClient.<String, Integer>getMapCache("t:v:pv");
String item = channel + "-" + app;
// mapCache.put() 该方法不报错
// 此处报错
mapCache.putIfAbsent(item, 0, 1, TimeUnit.DAYS);
// 此处报错
Integer pv = mapCache.addAndGet(item, 1);

说明

RMapCache不指定Codec的情况下默认使用JsonJacksonCodec
代码测试运行中使用 MarshallingCodec 编解码器

RedissonMapCache 类 addAndGetOperationAsync 方法指定了编解码器 StringCodec 
所以使用 getMapCache 方法最好指定 StringCodec 编解码器
commandExecutor.evalWriteAsync(name, StringCodec.INSTANCE,XXX)

或者value指定Integer类型使用 TypedJsonJacksonCodec 编解码器

正确使用

The correct setup to use addAndGet should be as follows:
RMapCache<String, Long> map = redisson.getMapCache("testMap", StringCodec.INSTANCE);
map.put("test", 1L);
map.addAndGet("test", 1L);

or

RMapCache<String, Integer> map = redisson.getMapCache("testMap", TypedJsonJacksonCodec.INSTANCE);
map.put("test", 1);
map.addAndGet("test", 1);

建议根据value类型使用编解码器,如int类型的计数器使用 IntegerCodec.INSTANCE (String转Integer)
RMapCache<String, Integer> mapCache = redissonClient.<String, Integer>getMapCache("key", IntegerCodec.INSTANCE);
String item = channel + "-" + xxx;
mapCache.putIfAbsent(item, 1, 1, TimeUnit.DAYS);
Integer pv = mapCache.addAndGet(item, 1);
在使用 Redisson 的 `bucket.get()` 方法时,如果遇到 `ClassNotFoundException`,通常表明序列化或反序列化过程中出现了找不到的问题Redisson 在进行分布式对象的存储和读取时,默认使用 Java 原生序列化机制,因此要求存储的对象及其依赖必须在反序列化时存在于路径中。 ### 异常原因分析 1. **路径缺失**:当从 Redisson 的 `RBucket` 中获取对象时,如果对象所属的未在当前 JVM 的路径中找到,就会抛出 `ClassNotFoundException`。 2. **版本不一致**:如果序列化时和反序列化时的定义不一致(如字段变化、包名不同等),也可能导致反序列化失败。 3. **自定义加载器问题**:某些容器或框架(如 OSGi、Web 容器)使用自定义加载器,可能导致加载失败。 ### 解决方案 #### 1. 确保路径完整 确保所有需要序列化的及其依赖都已正确打包并部署到应用中。例如,如果使用的是 Maven 项目,确保这些所在的模块已正确声明为依赖项,并被包含在最终的构建产物中。 #### 2. 使用 JSON 序列化替代 Java 原生序列化 为了避免路径问题,可以使用 JSON 序列化方式,如 Jackson 或 Gson。Redisson 支持自定义序列化器: ```java Config config = new Config(); JsonJacksonCodec jsonJacksonCodec = new JsonJacksonCodec(); config.setCodec(jsonJacksonCodec); RedissonClient redisson = Redisson.create(config); ``` 使用 JSON 序列化后,无需担心路径问题,因为对象会被转换为 JSON 字符串存储。 #### 3. 检查加载器 如果使用了自定义加载器,可以尝试为 Redisson 配置特定的加载器: ```java config.setClassLoader(Thread.currentThread().getContextClassLoader()); ``` #### 4. 使用 `tryGet()` 方法进行安全获取 Redisson 提供了 `tryGet()` 方法,可以在获取失败时返回 `null` 而不是抛出异常,适用于临时调试或容错处理: ```java RBucket<MyClass> bucket = redisson.getBucket("myBucket"); MyClass value = bucket.tryGet(); ``` #### 5. 启用日志调试 启用 Redisson 的调试日志输出,有助于定位序列化/反序列化过程中的具体错误: ```properties org.redisson.level=FINEST ``` ### 示例代码:使用 JSON 序列化获取 bucket 数据 ```java import org.redisson.Redisson; import org.redisson.api.RBucket; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.redisson.codec.JsonJacksonCodec; public class RedissonExample { public static void main(String[] args) { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); config.setCodec(new JsonJacksonCodec()); RedissonClient redisson = Redisson.create(config); RBucket<MyData> bucket = redisson.getBucket("myDataKey"); MyData data = bucket.get(); // 使用 JSON 反序列化,无需路径一致 System.out.println(data); redisson.shutdown(); } } class MyData { private String name; private int value; // getters and setters } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值