Java对象以Hash结构存入Redis详解

 更新时间:2023年08月29日 08:51:19   作者:Abstracted  
这篇文章主要介绍了Java对象以Hash结构存入Redis详解,和Java中的对象非常相似,却不能按照Java对象的结构直接存储进Redis的hash中,因为Java对象中的field是可以嵌套的,而Redis的Hash结构不支持嵌套结构,需要的朋友可以参考下

Java对象以Hash结构存入Redis

Redis中Hash存储结构:

Key:{
	filed: value,
	filed: value,
	filed: value,
	....
}

和Java中的对象非常相似,却不能按照Java对象的结构直接存储进Redis的hash中。因为Java对象中的field是可以嵌套的,而Redis的Hash结构不支持嵌套结构。(不允许套娃~)。

有的同学要问了,那我就是头铁,就要把带嵌套属性的对象存储redis的hash中,应该怎么办?

Spring对所有的RedisClient进行了封装,提供了一个RedisTemplate。那我们看看RedisTemplate中对hash结构的存储都接受什么参数?

在这里插入图片描述

从图中可以看出:

  • 一次存一个KV
  • 一次性将Map中的所有KV都存入
  • 如果不存在就存入

一次只存一个KV就不用说了。重点是第二个putAll方法。既然是Map,那我们不就是可以将带有嵌套属性的对象转成Map就可以存进Redis了吗?

但经过实践最终抛出了异常。正如上面已经说过的,Redis的Hash结构不允许套娃。而不带有嵌套属性的对象转成Map后可以正常存入。

对象转Map可以使用commons的BeanUtils中的toMap方法。

难道真的就没有解决办法了吗?其实Spring已经为我们提供了嵌套属性转Map的3中实现方案,也就是 HashMapper 接口

在这里插入图片描述

  • BeanUtilsHashMapper:内部依赖commons的BeanUtils将对象转Map,但是官方注释中也说明了这个实现类不支持嵌套属性。
  • ObjectHashMapper:内部使用的是RedisMappingConverter将给定的Java对象提供一个平面的映射,即支持嵌套属性。
  • Jackson2HashMapper:内部使用的是Jackon的ObjectMapper将对象转换成扁平的Map
  • DecoratingStringHashMapper: 没有什么特殊的,toHash方法实现了装饰器(增强)设计模式,对delegate.toHash的结果Map中的KV都进行String.valueOf()操作。

可以看出 ObjectHashMapper 和 Jackson2HashMapper 的效果相同,用那个都可以。

注意:Jackson2HashMapper在为对象生成Map时,内部对ObjectMapper配置了对Date类型的序列化规则,会将其换成时间戳Long类型。 在执行putAll时,内部会报ClassCastException Long cast to String,Long无法直接转换为String。此时可以使用DecoratingStringHashMapper对Jackson2HashMapper进行增强。

下面是一部分的示例代码和截图

@Autowired
    private RedisTemplate redisTemplate;
    /**
     * 测试Redis存Hash结构数据
     */
    @Test
    void testSaveRedisHash() throws JsonProcessingException {
        User user = new User();user.setUserId(111);user.setPassword("psw");user.setName("张三");user.setCreateTime(new Date());
        ObjectMapper objectMapper = new ObjectMapper();
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(RedisSerializer.string());
        // key, filed, value
        redisTemplate.opsForHash().put("testHash", "hashKey", "hashValue");
        // 直接写JSON,并没有什么卵用
        redisTemplate.opsForHash().put("testHash", "user", objectMapper.writeValueAsString(user));
        TestRedisHashObject testObj = new TestRedisHashObject(1, "测试时", new Date(), user);
        // 依赖第三方commons.beanUtils包
        redisTemplate.opsForHash().putAll("BeanUtilsHashMapper实现对象转hash",new BeanUtilsHashMapper<>(TestRedisHashObject.class).toHash(testObj));
        // flatmap为true,才开启json属性path扁平化。
        // jackson2HashMapper中默认的ObjectMapper对时间序列化成了long,而putAll方法中对long无法直接强转成string。会发生ClassCastException
        // decoratingStringHashMapper:将map中的所有kv都使用StringValueOf进行了增强
        redisTemplate.opsForHash().putAll("Jackson2HashMapper实现对象转hash",new DecoratingStringHashMapper<>(new Jackson2HashMapper(true)).toHash(testObj));
        // ObjectHashMapper返回的Map的泛型是Map<byte[], byte[]> 需要自己手动转换。不推荐使用
        // decoratingStringHashMapper:String.valueOf方法无法对byte[]进行转成字符串
        // redisTemplate.opsForHash().putAll("ObjectHashMapper实现对象转hash",new ObjectHashMapper().toHash(testObj));
    }
    /**
     * 测试Redis取Hash结构数据
     */
    @Test
    void testGetRedisHash(){
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(RedisSerializer.string());
        String key = "Jackson2HashMapper实现对象转hash";
        Object o = new Jackson2HashMapper(true).fromHash(redisTemplate.opsForHash().entries(key));
        TestRedisHashObject testObj = (TestRedisHashObject) o;
        System.out.println(testObj);
        Long newCount = redisTemplate.opsForHash().increment(key, "count", 10L);
        System.out.println("newCount = " + newCount);
        o = new Jackson2HashMapper(true).fromHash(redisTemplate.opsForHash().entries(key));
        testObj = (TestRedisHashObject) o;
        System.out.println(testObj);
		Object c = redisTemplate.opsForHash().get(key, "count");
        Long count = (Long) c;
        System.out.println("getCount = " + count);
    }

在这里插入图片描述

在这里插入图片描述

到此这篇关于Java对象以Hash结构存入Redis详解的文章就介绍到这了,更多相关Java对象存入Redis内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 更改Maven软件源为阿里云源的方法详解

    更改Maven软件源为阿里云源的方法详解

    这篇文章主要介绍了更改Maven软件源为阿里云源的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • swagger整合gateway实现文档集中化过程

    swagger整合gateway实现文档集中化过程

    本文介绍了如何将Swagger与Spring Cloud Gateway整合,实现API文档的集中化管理,通过Spring Boot的自动装配,配置了网关Swagger资源提供程序,实现了通过gateway路由的方式聚合Swagger文档,整个过程包括了文件夹结构、自动装配文件内容等详细步骤
    2026-02-02
  • java定义通用返回结果类ResultVO使用示例详解

    java定义通用返回结果类ResultVO使用示例详解

    这篇文章主要为大家介绍了java定义通用返回结果类ResultVO使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • SpringBoot整合Redis实现登录失败锁定功能(实例详解)

    SpringBoot整合Redis实现登录失败锁定功能(实例详解)

    本文我们已经探讨如何利用Redis来实现锁定账户的安全措施,以及通过SpringBoot整合Redis实现了这一功能,感兴趣的朋友跟随小编一起学习下吧
    2024-02-02
  • Java中的Caffeine加载与驱逐策略详解

    Java中的Caffeine加载与驱逐策略详解

    这篇文章主要介绍了Java中的Caffeine加载与驱逐策略详解,Caffeine是基于Java 8的高性能缓存库,可提供接近最佳的命中率,Caffeine与ConcurrentMap相应,但是不完全相同,本文主要介绍Caffeine,需要的朋友可以参考下
    2023-10-10
  • Java求素数和最大公约数的简单代码示例

    Java求素数和最大公约数的简单代码示例

    这篇文章主要介绍了Java求素数和最大公约数的简单代码示例,其中作者创建的Fraction类可以用来进行各种分数运算,需要的朋友可以参考下
    2015-09-09
  • 详解@ConditionalOnMissingBean注解的作用

    详解@ConditionalOnMissingBean注解的作用

    这篇文章主要介绍了详解@ConditionalOnMissingBean注解的作用,@ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,需要的朋友可以参考下
    2023-10-10
  • Spring Boot配置接口WebMvcConfigurer的实现

    Spring Boot配置接口WebMvcConfigurer的实现

    这篇文章主要介绍了SpringBoot配置接口WebMvcConfigurer的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Java编程实现从给定范围内随机N个不重复数生成随机数的方法小结

    Java编程实现从给定范围内随机N个不重复数生成随机数的方法小结

    这篇文章主要介绍了Java编程实现从给定范围内随机N个不重复数生成随机数的方法,结合实例形式较为详细的分析了java根据指定范围生成不重复随机数的相关操作技巧,需要的朋友可以参考下
    2017-04-04
  • 浅谈一下Servlet的定义以及运行原理

    浅谈一下Servlet的定义以及运行原理

    相信有很多刚入行的朋友会疑惑Servlet到底是个什么意思,那么这篇文章就来浅谈一下到底什么是Servlet,以及Servlet的原理与如何写一个Servlet,,需要的朋友可以参考下
    2023-03-03

最新评论