SpringBoot整合Redis调用lua脚本出现空指针异常(序列化器问题)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 一、问题描述业务中出现需要保证原子性的一系列缓存操作,所以决定使用lua脚本来保证原子性。但是调用过程中lua脚本抛出了异常:attempt to perform arithmetic on local ‘xxx’ (a nil value)发生异常的lua脚本代码(部分)

一、问题描述

业务中出现需要保证原子性的一系列缓存操作,所以决定使用lua脚本来保证原子性。


但是调用过程中lua脚本抛出了异常:attempt to perform arithmetic on local ‘xxx’ (a nil value)


发生异常的lua脚本代码(部分)

--- 省略...
local chosenCreditKey = "student:credits:chosen:" .. studentId
local chosenCredit = tonumber(redis.call("get", chosenCreditKey))
local maxCreditKey = "student:credits:max:" .. studentId
local maxCredit = tonumber(redis.call("get", maxCreditKey))
if chosenCredit + credits > maxCredit then --- 报错,提示chosenCredit为nil
    return 1
end
--- 省略...

二、问题分析

根据出现的异常描述,说的是尝试使用一个空值进行数学运算。

首先我尝试直接在代码中进行调试,尝试获取redis.call中get的值是什么,结果发现print语句输出的结果并不会出现在控制台

于是我直接在redis中运行脚本

ECHO "return redis.call("get", "xxx")" 0

很显然输出的值是nil

那么到这里就很清楚了,因为redis中存储的值并不能直接转换为数字,所以出现了空指针异常

三、问题解决

仔细观察第一次运行输出的值,我们不难发现这其实是带双引号的1而且双引号被转移导致了无法调用tonumber


也就是说只要我们存储的时候没有这个双引号就可以解决这个问题了


而之所以存储的时候会带上双引号是因为我使用的是自定义的redisTemplate进行插入,key和value的泛型都设置为了string类型,并且在定义该类时选用了Jackson2JsonRedisSerializer<String>作为值的序列化器。


因为默认使用的JdkSerializationRedisSerializer序列器,需要被序列化Class实现Serializable接口,而且Redis数据库中数据很不直观


而这个序列化器在处理字符串时会自动为字符串带上双引号进行存储


那么自然也就有对应的两种解决方法:


既然是因为这个序列化器导致的存入数据带上了双引号,那么我们更换序列化器就可以了,比如StringRedisSerializer,就可以存入字符串时不带双引号

因为是存储字符串时才带上双引号,那么我们也可以选择将redisTemplate的值的泛型更改为object,然后插入数据时直接插入数字,那么自然也不会带上双引号

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6天前
|
NoSQL Java Redis
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
379 0
|
6天前
|
消息中间件 NoSQL Java
springboot redis 实现消息队列
springboot redis 实现消息队列
70 1
|
6天前
|
NoSQL Java 测试技术
字节二面:Spring Boot Redis 可重入分布式锁实现原理?
字节二面:Spring Boot Redis 可重入分布式锁实现原理?
178 1
|
6天前
|
消息中间件 NoSQL Java
Redis Streams在Spring Boot中的应用:构建可靠的消息队列解决方案【redis实战 二】
Redis Streams在Spring Boot中的应用:构建可靠的消息队列解决方案【redis实战 二】
315 1
|
6天前
|
JSON 安全 Java
Spring Boot 序列化、反序列化
本文介绍了Spring Boot中的序列化和反序列化。Java提供默认序列化机制,通过实现Serializable接口实现对象到字节流的转换。Spring Boot默认使用Jackson处理JSON,可通过注解和配置自定义规则。然而,序列化可能引发安全问题,建议使用白名单、数据校验和安全库。最佳实践包括使用标准机制、自定义规则及注意版本控制。文章还提醒关注性能并提供了相关参考资料。
68 2
|
6天前
|
NoSQL Java Redis
Spring Boot 监听 Redis Key 失效事件实现定时任务
Spring Boot 监听 Redis Key 失效事件实现定时任务
66 0
|
6天前
|
NoSQL Java 数据库连接
springboot整合Redis中连接池jedis与lettuce的对比和实现
springboot整合Redis中连接池jedis与lettuce的对比和实现
401 0
|
6天前
|
算法 NoSQL Java
springboot整合redis及lua脚本实现接口限流
springboot整合redis及lua脚本实现接口限流
96 0
|
6天前
|
JSON NoSQL Java
深入浅出Redis(十三):SpringBoot整合Redis客户端
深入浅出Redis(十三):SpringBoot整合Redis客户端
|
6天前
|
缓存 NoSQL Java
springboot业务开发--springboot集成redis解决缓存雪崩穿透问题
该文介绍了缓存使用中可能出现的三个问题及解决方案:缓存穿透、缓存击穿和缓存雪崩。为防止缓存穿透,可校验请求数据并缓存空值;缓存击穿可采用限流、热点数据预加载或加锁策略;缓存雪崩则需避免同一时间大量缓存失效,可设置随机过期时间。文章还提及了Spring Boot中Redis缓存的配置,包括缓存null值、使用前缀和自定义过期时间,并提供了改造代码以实现缓存到期时间的个性化设置。