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

发现取出来的值并非是空值而是"{\"1\"}",随后再运行

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

很显然输出的值是nil

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


三、问题解决

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

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

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

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

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


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


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


2.可以选择将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
相关文章
|
29天前
|
NoSQL Java Redis
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
354 0
|
20小时前
|
缓存 NoSQL Java
springboot业务开发--springboot集成redis解决缓存雪崩穿透问题
该文介绍了缓存使用中可能出现的三个问题及解决方案:缓存穿透、缓存击穿和缓存雪崩。为防止缓存穿透,可校验请求数据并缓存空值;缓存击穿可采用限流、热点数据预加载或加锁策略;缓存雪崩则需避免同一时间大量缓存失效,可设置随机过期时间。文章还提及了Spring Boot中Redis缓存的配置,包括缓存null值、使用前缀和自定义过期时间,并提供了改造代码以实现缓存到期时间的个性化设置。
|
6天前
|
存储 NoSQL 调度
Redis Lua脚本:原子性的真相揭秘
【4月更文挑战第20天】
20 0
Redis Lua脚本:原子性的真相揭秘
|
12天前
|
NoSQL 数据可视化 Java
Springboot整合redis
Springboot整合redis
|
13天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
160 10
|
22天前
|
NoSQL Java Redis
Springboot整合redis
Springboot整合redis
|
25天前
|
NoSQL Java Redis
lua脚本做redis的锁
这段内容是关于使用Redis实现分布式锁的Java代码示例。`RedisLock`类包含`lock`和`unlock`方法,使用`StringRedisTemplate`和Lua脚本进行操作。代码展示了两种加锁方式:一种带有过期时间,另一种不带。还提到了在加锁和解锁过程中的异常处理,并提供了相关参考资料链接。
18 3
|
27天前
|
存储 NoSQL 数据处理
Redis Lua脚本:赋予Redis更强大的逻辑与功能
Redis Lua脚本:赋予Redis更强大的逻辑与功能
|
2月前
|
存储 C#
C#中的序列化和反序列化
C#中的序列化和反序列化
12 0
|
2月前
|
存储 Java 数据库