Redis/Redisson提示异常:Unexpected token (START_OBJECT), expected VALUE_STRING: need String, Number......

解决Redis中Unexpected token (START_OBJECT)错误

在使用Redis存储复杂对象(如Java对象)时,我们可能会遇到这样的错误信息:

Unexpected token (START_OBJECT), expected VALUE_STRING: need String, Number or Boolean value that contains type id (for subtype of java.lang.Object)

这个错误通常发生在尝试将一个复杂对象直接存储到Redis中,而没有正确地序列化。

问题描述

当我们尝试从Redis读取一个预期为字符串、数字或布尔值的值时,如果实际存储的是一个未正确序列化的复杂对象,就会遇到上述错误。

排查过程

1. 配置Redisson客户端

根据网上的教程,我尝试配置Redisson客户端以支持JSON序列化,特别是处理LocalDateTime异常:

@Bean
public RedissonClient redisson() throws IOException {
    Config config = Config.fromYAML(configFile.getInputStream());
    // 修复引入Redisson存储json序列化配置时提示LocalDateTime异常
    JsonJacksonCodec jacksonCodec = new JsonJacksonCodec();
    jacksonCodec.getObjectMapper()
            // 补充支持jsr310
            .registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    config.setCodec(jacksonCodec);
    // 修复引入Redisson存储json序列化配置时提示LocalDateTime异常
    return Redisson.create(config);
}

然而,这个配置并没有解决问题。

检查Redis中的数据

进一步排查时,我去Redis中查看了存储的数据,发现存储的是数组,而不是预期的对象类型。这可能是导致异常的原因。

指定存储的对象类型

怀疑是因为Redis中存储的数据类型不正确导致异常,我在设置Redis时再次指定了存储的对象类型。这次,我确保了存储的数据是正确序列化的JSON字符串,而不是数组或其他类型。

方案一

确保在存储到Redis之前,将复杂对象正确序列化为JSON字符串。这可以通过使用Jackson或Gson等库来实现。以下是使用Jackson和Gson序列化和反序列化的示例代码:

方案二

使用Kryo5Codec
另一方面,如果使用Kryo5Codec,则不需要指定返回的类型,因为Kryo5Codec可以自动处理对象的序列化和反序列化。

# redisson.yaml
# 编码。默认值: org.redisson.codec.JsonJacksonCodec
codec: !<org.redisson.codec.Kryo5Codec> {}
# 线程池数量。默认值: 当前处理核数量 * 2
threads: 16
# Netty线程池数量。默认值: 当前处理核数量 * 2
nettyThreads: 32
# 传输模式。默认值: NIO
transportMode: "NIO"
# 监控锁的看门狗超时,单位:毫秒。默认值: 30000
lockWatchdogTimeout: 30000
# 是否保持订阅发布顺序。默认值: true
keepPubSubOrder: true
# Redisson 单实例配置
singleServerConfig:
  # 节点地址。格式:redis://host:port
  address: "redis://xxx.xxx.xxx.xxx:xxxx"
  # 密码。默认值: null
  password: null
  # 数据库编号。默认值: 0
  database: 0
  # 客户端名称(在Redis节点里显示的客户端名称)。默认值: null
  clientName: null
  # 连接超时,单位:毫秒。默认值: 10000
  connectTimeout: 10000
  # 命令等待超时,单位:毫秒。默认值: 3000
  timeout: 3000
  # 命令失败重试次数。默认值: 3
  retryAttempts: 3
  # 命令重试发送时间间隔,单位:毫秒。默认值: 1500
  retryInterval: 1500
  # 最小空闲连接数。默认值: 32
  connectionMinimumIdleSize: 24
  # 连接池大小。默认值: 64
  connectionPoolSize: 64
  # 单个连接最大订阅数量。默认值: 5
  subscriptionsPerConnection: 5
  # 发布和订阅连接的最小空闲连接数。默认值: 1
  subscriptionConnectionMinimumIdleSize: 1
  # 发布和订阅连接池大小。默认值: 50
  subscriptionConnectionPoolSize: 50
  # DNS监测时间间隔,单位:毫秒。默认值: 5000
  dnsMonitoringInterval: 5000
  # 连接空闲超时,单位:毫秒。默认值: 10000
  idleConnectionTimeout: 10000

结论

通过确保在存储到Redis之前将复杂对象正确序列化为JSON字符串,并在读取时正确反序列化,我们可以避免遇到Unexpected token (START_OBJECT)错误。这要求我们在存储和读取时使用相同的序列化/反序列化方法,并确保数据类型一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值