SpringBoot2.x整合Redis使用FastJson序列化

与Redis相关知识可查看《Redis系列记录》

(十五)Springboot缓存

一、相关配置

1.1 pom.xml

<!-- spring-boot-starter-data-redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        <!-- 连接池 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

1.2 application.properties

spring.cache.type=redis
# Redis数据库索引(默认为0)
spring.redis.database=0  
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379  
# Redis服务器连接密码(默认为空)
#spring.redis.password=123456
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.max-active=200  
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.max-wait=-1  
# 连接池中的最大空闲连接
spring.redis.lettuce.max-idle=10 
# 连接池中的最小空闲连接
spring.redis.lettuce.min-idle=0  
# 连接超时时间(毫秒)
spring.redis.timeout=1000ms

logging.level.com.example.redisdemo=debug

1.3 RedisConfig

@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public RedisSerializer fastJson2JsonRedisSerialize(){
        return new FastJson2JsonRedisSerialize<Object>(Object.class);
    }

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory,RedisSerializer fastJson2JsonRedisSerialize){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置Key的序列化采用StringRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        //设置值的序列化采用FastJsonRedisSerializer
        redisTemplate.setValueSerializer(fastJson2JsonRedisSerialize);
        redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerialize);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // 设置缓存的默认过期时间,也是使用Duration设置
        config = config.entryTtl(Duration.ofMinutes(5))
                // 设置 key为string序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                // 设置value为fastJson序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJson2JsonRedisSerialize()))
                // 不缓存空值
                .disableCachingNullValues();
        // 使用自定义的缓存配置初始化一个cacheManager
        return RedisCacheManager
                .builder(redisConnectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
    }
}

1.4  FastJson2JsonRedisSerialize

public class FastJson2JsonRedisSerialize<T> implements RedisSerializer<T> {

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private Class<T> clazz;

    static {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        //如果遇到反序列化autoType is not support错误,请添加并修改一下包名到bean文件路径
        //ParserConfig.getGlobalInstance().addAccept("com.example.redisdemo.domain");
    }

    public FastJson2JsonRedisSerialize(Class clazz){
        super();
        this.clazz = clazz;
    }


    /**
     * 序列化
     * @param t
     * @return
     * @throws SerializationException
     */
    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (null == t){
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    /**
     * 反序列化
     * @param bytes
     * @return
     * @throws SerializationException
     */
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (null == bytes || bytes.length <= 0){
            return null;
        }
         String str = new String(bytes,DEFAULT_CHARSET);
        return (T) JSON.parseObject(str,clazz);
    }
}

二、测试

2.1 User

public class User implements Serializable {

    private static final long serialVersionUID = 8391377903506428591L;
    private Integer id;

    private String username;

    private String password;

    public User(){
        super();
    }

    public User(Integer id, String username, String password){
        this.id = id;
        this.username = username;
        this.password = password;
    }
   getter... setter... toString()...
}

2.2 UserService   UserServiceImpl

public interface UserService {

    public User addUser(User user);

    public User getUser(Integer id);

    public void delUser(Integer id);
}

 这里不用Mapper了,使用Map来模拟一下数据库操作,

@CacheConfig(cacheNames = "user")
@Service("userService")
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    private static final Map<String,Object> usersMap = new HashMap<>();

    @Override
    @CachePut(key = "#user.id")
    public User addUser(User user) {
        usersMap.put(user.getId().toString(),user);
        logger.info("存入数据库【User】= {}",user);
        return user;
    }

    @Override
    @Cacheable(key = "#id",unless = "#result == null ")
    public User getUser(Integer id){
        User user = (User) usersMap.get(id.toString());
        logger.info("从数据库获取【User】= {}",user);
        return user;
    }

    @Override
    @CacheEvict(key = "#id")
    public void delUser(Integer id) {
        usersMap.remove(id.toString());
        logger.info("从数据库删除【User】");
    }
}

2.3 Test

    @Test
    void testOne() {
         userService.addUser(new User(1,"aa","123"));
         User user = userService.getUser(1);
         logger.debug("【User】={}",user);
    }

2.4 结果

 这里可以看到只打印了添加日志和最后的查询结果,并没有打印查询日志,所以证明缓存生效。

三、相关知识点与坑

3.1 报com.alibaba.fastjson.JSONException: autoType is not support

解决方法:在FastJson2JsonRedisSerialize 类中添加   这两句代码都可以解决反序列化问题

  static {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        //如果遇到反序列化autoType is not support错误,请添加并修改一下包名到bean文件路径
        //ParserConfig.getGlobalInstance().addAccept("com.example.redisdemo.domain");
    }

3.2 Cache 'redisCache' does not allow 'null' values

解决方法:添加unless = "#result == null"

 @Cacheable(key = "#id",unless = "#result == null ")

缓存相关注解可查看第(十五)篇:Springboot缓存


四、RedisTemplate

上文中使用注解来完成缓存操作,下文中使用redisTemplate来操作缓存

在测试类中添加: 

@Resource(name = "redisTemplate")
    private ValueOperations<String,Object> vo;

  @Test
    void testFour(){
        vo.set("java",new User(1,"bb","111"));
        User user = (User) vo.get("java");
        System.out.println(user);
    }

 执行: 也是好用的

 那么为什么redisTemplate可以直接注入给五种数据类型的XXOperations使用呢?原来有属性编辑器

 

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Redis 是一个内存数据库,主要用于存储键值对,其数据结构丰富,性能非常高,常用于缓存和消息队列等场景。Fastjson 是阿里巴巴开源的一个 Java 编写的高性能功能完备的 JSON 库,用于将 Java 对象转换为 JSON 字符串,以及将 JSON 字符串解析为 Java 对象。 当你想要在 Redis使用 Fastjson 进行序列和反序列时,通常会遇到这样的情况:你需要将 Java 对象(比如 POJOs)保存到 Redis,然后在需要的时候从 Redis 读取并转换回 Java 对象。这是一个基本的流程: 1. **序列**: - 将 Java 对象转换为 JSON 字符串:在发送数据到 Redis 之前,你可以使用 Fastjson 的 `Object.toJSONString()` 方法将 Java 对象转换成 JSON。例如: ```java User user = new User("John", 25); String json = JSONObject.toJSONString(user); String key = "user:" + user.getId(); // 假设 userId 是唯一标识 redis.set(key, json); ``` 2. **存储**: - 将 JSON 字符串存储到 Redis 相应的 key 中。 3. **反序列**: - 当从 Redis 读取数据时,可以通过 `redis.get(key)` 获取 JSON 字符串,然后用 Fastjson 的 `JSONObject.parseObject(json, User.class)` 将 JSON 解析回 Java 对象: ```java String retrievedJson = redis.get(key); User retrievedUser = JSONObject.parseObject(retrievedJson, User.class); ``` **相关问题--:** 1. Fastjson序列和反序列过程中的主要优势是什么? 2. 如何处理 Redis 中的 JSON 数据,以便支持复杂的数据结构? 3. Redis 有没有内置的 JSON 支持,为什么要引入 Fastjson

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LoneWalker、

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值