RedisTemplate序列化方式转换

不足的地方,或者理解有误的地方,评论区欢迎!!❀ 🌙❀

1 Redis 的几种序列方式

Redis存储序列化方式,常用的有以下几种:

  • JdkSerializationRedisSerializer:将数据序列化为对象
  • StringRedisSerializer:简单的字符串序列化
  • GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
  • JacksonJsonRedisSerializer: 序列化object对象为json字符串
  • Jackson2JsonRedisSerializer:将数据序列化为json ,序列化带泛型的数据时,会以map的结构进行存储,反序列化是不能将map解析成对象。跟JacksonJsonRedisSerializer实际上是一样的
  • GenericJackson2JsonRedisSerializer:将数据序列化为json,但这个时保存了对象包名 方便反序列化

Jackson2JsonRedisSerializer 和 GenericJackson2JsonRedisSerializer 区别

2 StringRedisTemplate和RedisTemplate的区别及使用方法

https://www.cnblogs.com/MyYJ/p/10778874.html

3 注释解析

spring framework中的注解

@EnableCaching:启用注解缓存,若使用该注解,就不需要在XML文件中配置cache manager

@Cacheable : 开启缓存,使用这个注解的方法在执行后会缓存其返回结果。【写在方法上】
@Cacheable(cacheNames = “studentCache”, key = “#id”)

@CacheEvict:用完缓存后,清除缓存【写在方法上】
@CacheEvict(cacheNames=“cacheValue”,key = “#id”)

@CachePut:每次用完缓存,更新缓存【写在方法上】

@cacheConfig: 【写在类上】

https://www.cnblogs.com/dianzan/p/11209846.html【Spring中注解使用缓存】

4 缓存模式存储

4.1 参考链接

SpringCloud用Spring Cache的方式使用Redis缓存 ※
springboot使用@EnableCaching实现缓存 ※

4.2 其中遇到的问题

1.org.springframework.cache.support.SimpleValueWrapper cannot be cast to java.util.Map
存储对象用map示例时,获取缓存报错,后改用javaObject为示例

2.java.lang.IllegalStateException

java.lang.IllegalStateException: No CacheResolver specified, and no unique bean of type CacheManager found. Mark one as primary or declare a specific CacheManager to use.
	at org.springframework.cache.interceptor.CacheAspectSupport.afterSingletonsInstantiated(CacheAspectSupport.java:223) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:896) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	......

原因:两个配置类重复
解决方法:两个cacheManager在其中一个上面加**@Primary**,指定一个默认的

4.3 完整代码

// 配置文件
// @EnableCaching 开启缓存支持;

@EnableCaching
@Configuration
public class CacheConfig {

    //放入缓存
    @Bean
    @Primary
    public ConcurrentMapCacheManager cacheManagerTwo(){
        ConcurrentMapCacheManager mapCacheManager = new ConcurrentMapCacheManager();
        //cacheManager.setStoreByValue(true); //true表示缓存一份副本,否则缓存引用
        return mapCacheManager;
    }
}
// 控制类
// @Cacheable-------使用这个注解的方法在执行后会缓存其返回结果。
// @CacheEvict--------使用这个注解的方法在其执行前或执行后移除Spring Cache中的某些元素。


@RestController
@AllArgsConstructor
@RequestMapping("/test")
public class TestController {
    @Autowired
    private CacheConfig cacheConfig;

    /**
     * @Cacheable-------使用这个注解的方法在执行后会缓存其返回结果。
     */
    @Cacheable(cacheNames = "cacheValue",key = "#id")
    @GetMapping("/getInfo")
    public Result getInfo(@ApiParam(value="主键id") Integer id){
        JSONObject json = new JSONObject();
        json.put("code",1);
        json.put("msg","缓存内容");
        json.put("date", DateTimeUtil.formatDefault(new Date()));
        System.out.println("json==>"+json);
        return Result.success(json);
    }

    /**
     * 获取缓存信息
     */
    @GetMapping("/getCache")
    public Result getCache(){
        Cache cache = cacheConfig.cacheManagerTwo().getCache("cacheValue");
        System.out.println("Cache.getName===>"+cache.getName()); //Cache.getName===>cacheValue
        System.out.println("Cache===>"+cache.get(1));
        return Result.success(cache);
    }

    /**
     *  修改缓存信息
     *  修改删除 都可以用这个 @CacheEvict
     */
    @CacheEvict(cacheNames="cacheValue",key = "#id")
    @PutMapping("/update")
    public Result update(@RequestParam(value = "id")Integer id){
        JSONObject json = new JSONObject();
        json.put("code",2);
        json.put("msg","删除缓存信息");
        json.put("date", DateTimeUtil.formatDefault(new Date()));
        System.out.println("json==>"+json);
        return Result.success(json);
    }
}
◀  执行的返回值

1. 查询,将结果直接放入缓存  127.0.0.1:9528/test/getInfo?id=1
{
    "code": 0,
    "message": "成功",
    "data": {
        "msg": "缓存内容",
        "date": "2021-11-09 14:12:56",
        "code": 1
    },
    "exception": false,
    "error": null
}

◀  执行的返回值

2. 查询缓存  127.0.0.1:9528/test/getCache
{
    "code": 0,
    "message": "成功",
    "data": {
        "allowNullValues": true,
        "name": "cacheValue",
        "nativeCache": {
            "1": {
                "code": 0,
                "message": "成功",
                "data": {
                    "msg": "缓存内容",
                    "date": "2021-11-09 14:12:56",
                    "code": 1
                },
                "exception": false,
                "error": null
            }
        },
        "storeByValue": false
    },
    "exception": false,
    "error": null
}
◀  执行的返回值

3.1清除缓存  127.0.0.1:9528/test/update?id=1
{
    "code": 0,
    "message": "成功",
    "data": {
        "msg": "删除缓存信息",
        "date": "2021-11-09 14:47:41",
        "code": 2
    },
    "exception": false,
    "error": null
}

3.2 再次查询缓存  127.0.0.1:9528/test/getCache  数据已删除
{
    "code": 0,
    "message": "成功",
    "data": {
        "allowNullValues": true,
        "name": "cacheValue",
        "nativeCache": {},
        "storeByValue": false
    },
    "exception": false,
    "error": null
}

5 redisTemplate不同序列化

5.1 参考链接

https://blog.csdn.net/weixin_45941687/article/details/118933149
【RedisTemplate操作redis时,可视化工具查看,值前总会有一串“\xAC\xED\x00\x05t\x00\x”】

https://www.cnblogs.com/liuyi-clover/p/9406598.html
【JAVA操作ObjectMapper类】

https://www.cnblogs.com/wangzhuxing/p/10198347.html
【springboot系列十一、redisTemplate和stringRedisTemplate对比、redisTemplate几种序列化方式比较】

https://blog.csdn.net/bai_bug/article/details/81222519
【Jackson2JsonRedisSerializer和GenericJackson2JsonRedisSerializer的区别】

5.2 配置方式一 - GenericJackson2JsonRedisSerializer

【我下载了redis可视化工具RDM,方便查看数据,如果你下载了其他的可视化工具,就用你当前工具❀】

pom.xml依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

RedisConfig配置文件

package com.nanodata.mole.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;


@Configuration
public class RedisConfig {
    @Autowired
    private RedisTemplate redisTemplate;

    @Bean
    public RedisTemplate  redisTemplateInit(){
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

/**
* 这个是前辈写在这的,暂时未理解它的用处,知道的欢迎评论区告诉我,蟹蟹
*/
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .entryTtl(Duration.ofHours(1))
                ; // 设置缓存有效期一小时

        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                .cacheDefaults(redisCacheConfiguration).build();
    }

}

在这里插入图片描述

5.2 配置方式二 - GenericJackson2JsonRedisSerializer(hash key 和value)

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

RedisConfig配置文件

package com.nanodata.mole.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

import java.time.Duration;

@Configuration
public class RedisConfig {
   @Autowired
    private RedisTemplate redisTemplate;

    /** 该方式也可以 */

    @Bean
    public RedisTemplate  redisTemplateInit(){
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        // 设置hash key 和value序列化模式 ♥
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }
}

在这里插入图片描述

5.3 配置方式三 - Jackson2JsonRedisSerializer

pom.xml

        <!-- redis -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

RedisConfig配置文件

package com.nanodata.mole.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

@Configuration
public class RedisConfig {
    @Autowired
    private RedisTemplate redisTemplate;
    
    @Bean
    public RedisTemplate<String, Object> redisTemplateInit(RedisConnectionFactory redisConnectionFactory)  {
//        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);


        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        om.activateDefaultTyping(om.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);

        // 值采用json序列化
        redisTemplate.setValueSerializer(jacksonSeial);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        // 设置hash key 和value序列化模式
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jacksonSeial);

        // 设置支持事物
        redisTemplate.setEnableTransactionSupport(true);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

在这里插入图片描述

总结对比

使用Jackson2JsonRedisSerializer需要指明序列化的类Class,可以使用Obejct.class

2、使用GenericJacksonRedisSerializer比Jackson2JsonRedisSerializer效率低,占用内存高。

3、GenericJacksonRedisSerializer反序列化带泛型的数组类会报转换异常,解决办法存储以JSON字符串存储。

4、GenericJacksonRedisSerializer和Jackson2JsonRedisSerializer都是以JSON格式去存储数据,都可以作为Redis的序列化方式。

该片段总结来自-->原文链接:https://blog.csdn.net/bai_bug/article/details/81222519

5.4 问题

  1. Error:(35,37) java: 无法访问com.fasterxml.jackson.databind.JavaType
    解决方式:pom.xml添加如下依赖,重启服务

     <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
     </dependency>
    
  2. RedisTemplate配置的jackson.ObjectMapper里的一个enableDefaultTyping方法过期解决
    解决方式如下

// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
//      om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        om.activateDefaultTyping(om.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.NON_FINAL);

RedisTemplate配置的jackson.ObjectMapper里的一个enableDefaultTyping方法过期解决
【https://www.cnblogs.com/exmyth/p/13794524.html】

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值