Redis Hash序列化存储的问题及解决方案

 更新时间:2022年11月16日 11:07:40   作者:月未明  
这篇文章主要介绍了Redis Hash序列化存储的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

这里说的是Spring Data Redis(一下简称SDR)设置Hash存储的序列化。

SDR序列化方式有多种

如:

  • StringRedisSerializer
  • JdkSerializationRedisSerializer
  • Jackson2JsonRedisSerializer
  • OxmSerializer
  • 等等

目前我有个需求,是将数据用hash的形式存到Redis数据库中,在网上搜了下实现方式,部分代码如下:

    @Bean
    public RedisTemplate<String,Object> redisTemplate(){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
        return redisTemplate;
    }

    /**
     * 设置数据存入 redis 的序列化方式
     *
     * @param redisTemplate
     * @param factory
     */
    private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
    }


    /**
     * 实例化 HashOperations 对象,可以使用 Hash 类型操作
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

对Redis的存储设置是我自己写的

    /**
     * 添加
     *
     * @param key    key
     * @param filed    filed
     * @param domain 对象
     */
    public void hset(String key,String filed,Object domain){
        System.out.println("开始使用filed设置");
        hashOperations.put(key, filed, domain);
    }

    /**
     * 查询
     *
     * @param key 查询的key
     * @param field 查询的field
     * @return
     */
    public Object hget(String key,String field) {
        return hashOperations.get(key, field);
    }

方法:

    @RequestMapping("/mytest")
    public Object myTest() {

        redisUtils.hset("mykey","myfield","myvalue");

       return redisUtils.hget("mykey","myfield");
    }

Hash的存储跟String有些不同,从表面上看Hash多了个field,这个自己稍微想下就可以理解了。

执行上面的代码后,用客户端查看所存储的值:

上图显示的是乱码。

用redis-cli查看:

这里显示的是我存的值myvalue前多了些东西,这是序列化的时候所加的一些东西。

执行方法时前端得到的值:

这里可见从redis中取出的值是跟我存入的完全一样的(这是因为取出的时候Spring有做反序列化处理)。

如果从redis-cli中直接存储:

host:6379> hset mykey2 myfield2 myvalue2
(integer) 1
host:6379> hget mykey2 myfield2
"myvalue2"

查看客户端中的值:

在这里存入的hash显示的是正常的。

所以我猜测之前redis桌面客户端显示“不正常”的原因应该是出在序列化的时候。

更改序列化方法

改为StringRedisSerializer方式(一般key都是字符串,所以继续使用StringRedisSerializer,这里把Hash的value序列化改为StringRedisSerializer):

    /**
     * 设置数据存入 redis 的序列化方式
     *
     * @param redisTemplate
     * @param factory
     */
    private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
    }

查看客户端的值:

这时显示OK了,redis-cli中显示的也是OK的。

所以,我们遇到的问题貌似解决了。

因为我要存储的是hash,而hashOperations为我们提供了另外一个方法putAll,这个方法支持对HashMap的操作。

代码:

    /**
     * 添加
     *
     * @param key    key
     * @param hm    要存入的hash表
     */
    public void hset(String key, HashMap<String,Object> hm){
        System.out.println("开始使用hashmap设置");
        hashOperations.putAll(key,hm);
    }

因为我的hashmap中要存的值包含时间,所以就要把值设为Object,代码:

    @RequestMapping("/hm")
    public void hmsetTest() {

        HashMap<String,Object> hm =new HashMap<String,Object>();

        hm.put("myFieldKey","myFieldKey");
        hm.put("createTime",new Date());

        redisUtils.hset("mykey",hm);
    }

执行结果:

这时在调用的时候直接报错了,说是Date类型无法转String。

回到单个值存入的方法上:

    public void hset(String key,String filed,Object domain){
        System.out.println("开始使用filed设置");
        hashOperations.put(key, filed, domain);
    }

用这里执行Date的存储,结果还是包这个异常。

由此可见,使用StringRedisSerializer序列化并不能解决我们的问题,而且还有使用的限制。OxmSerializer这个东西我不太熟悉,所以没有测试。

使用Jackson2JsonRedisSerializer

更改序列化方式

redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));

执行单个日期操作结果如下:

这里显示的日期被转成时间戳形式存储的。

执行hashmap:

结果显示执行的也是成功的,如果跟StringRedisSerializer比较会发现,存储字符串的时候值得最外层会被加上“”。

继续使用JdkSerializationRedisSerializer

可以正常存储,但是显示形式一样不是我们期望的。

对于这个问题我网上有种解决方法,在redis-cli中查看的时候使用–raw指令

即启动指令为:redis-cli –raw。这种方式也可以正常的查看中文。但是查看的时候日期依然有问题,而且字符串前边会多些东西(t)。

OxmSerializer这个东西我不熟悉,所以就没有测试,但是网上一般都说建议使用JdkSerializationRedisSerializer,而且这种效率是最高的,没办法,毕竟是原生的。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Redis异步队列的实现及应用场景

    Redis异步队列的实现及应用场景

    异步队列是一种底层基于异步 I/O 模型的消息队列,用于在分布式系统中进行同步和异步的通讯和协作,本文主要介绍了Redis异步队列的实现及应用场景,感兴趣的可以了解一下
    2023-12-12
  • Redis全局ID生成器的实现

    Redis全局ID生成器的实现

    全局ID生成器,是一种在分布式系统下用来生成全局唯一ID的工具,本文主要介绍了Redis全局ID生成器的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Redis 持久化 RDB 与 AOF的执行过程

    Redis 持久化 RDB 与 AOF的执行过程

    本文给大家记录Redis 持久化RDB 与 AOF的执行过程与配置,通过内部触发 RDB 场景分析Redis 持久化 RDB的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-11-11
  • redis限流的实际应用

    redis限流的实际应用

    这篇文章主要介绍了redis限流的实际应用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • redis适合场景八点总结

    redis适合场景八点总结

    在本篇文章中我们给大家整理了关于redis适合什么场景的8点知识点内容,需要的朋友们参考下。
    2019-06-06
  • Redis Value过大问题(键值过大)

    Redis Value过大问题(键值过大)

    这篇文章主要介绍了Redis Value过大问题(键值过大),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Redis批量删除key的命令详解

    Redis批量删除key的命令详解

    这篇文章主要介绍了Redis批量删除key的命令详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • redis实现加锁的几种方法示例详解

    redis实现加锁的几种方法示例详解

    这篇文章主要给大家介绍了关于redis实现加锁的几种方法,加锁命令分别是INCR、SETNX和SET,文中给出了详细的示例代码,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-09-09
  • Win10下通过Ubuntu安装Redis的过程

    Win10下通过Ubuntu安装Redis的过程

    这篇文章主要介绍了Win10下通过Ubuntu安装Redis,在安装Ubuntu需要先打开Windows功能,接着创建一个用户及密码,本文给大家介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • Redis恢复被移除集群的服务器实操步骤

    Redis恢复被移除集群的服务器实操步骤

    这篇文章主要为大家介绍了Redis恢复被移除集群的服务器实操步骤,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07

最新评论