IDEA-SpringBoot整合Redis缓存实现

在SpringBoot中,数据的管理缓存依赖于Spring框架中相关的缓存管理器接口。
	如果程序中没有定义类型为cacheManager的Bean组件或者是名为cacheResolver的cacheResolver缓存解析器,
SpringBoot将尝试按照指定顺序选择并启用缓存组件。
	如果没有任何缓存组件,会默认使用Simple缓存组件进行管理,它是默认的缓存管理组件,默认使用内存中的ConcurrentHashMap进行缓存存储。

基于注解的Redis缓存实现

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  • Redis服务连接配置
# Redis服务地址
spring.redis.host=127.0.0.1
# Redis服务连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
  • 使用@Cacheable、@CachePut、@CacheEvict注解定制缓存管理。对先前的CommentService进行修改。
@Service
public class CommentService {
    //自定义一个业务操作类,使用注入的CommentRepository实例对象完成对Comment评论数据的查询修改和删除操作
    @Autowired
    private CommentRepository commentRepository;
    //根据评论id查询评论信息  unless = "#result==null":表示只有查询结果不为空才会对结果数据进行缓存存储
    //没有对key值进行标记,将会使用默认参数值comment_id进行数据保存,缓存更新时必须使用同样的key
    @Cacheable(cacheNames="comment",unless = "#result==null")
    public Comment findById(int comment_id){
        Optional<Comment> optional = commentRepository.findById(comment_id);
        return optional.orElse(null);
    }
    @CachePut(cacheNames="comment",key="#result.id")
    public Comment updateComment(Comment comment){
        commentRepository.updateComment(comment.getAuthor(),comment.getId());
        return comment;
    }
    @CacheEvict(cacheNames="comment")
    public void deleteComment(int comment_id){
        commentRepository.deleteById(comment_id);
    }
}
  • 基于注解的Redis查询缓存测试
    • 我们已经添加了Redis的缓存依赖和Redis服务连接配置,@EnableCaching开启了注解的缓存管理
    • 此时进行测试会出现IllegalArgumentException非法参数异常,要求对应Comment实体类必须实现序列化
    • 在Comment实体类中实现Serializable序列化接口(对实体类对象进行缓存存储必须实现序列化)
public class Comment implements Serializable {
	.....
  • 修改后测试通过,效果符合预期
    • 可以发现在Redis数据库中,缓存的数据的唯一标识key值是名称空间+参数值的字符串形式出现
    • value值是经过JDK默认序列格式化后的HEX格式存储(实际开发中会自定义数据的序列化格式)
      在这里插入图片描述

基于API的Redis缓存实现

  • 除基于注解形式实现外,开发中常用的方式为——基于API的Redis缓存实现
  • 使用Redis API进行业务数据缓存管理
    • 使用comment_+id方式,避免与上面的注解形式混淆
@Service
public class ApiCommentService {
    @Autowired
    private CommentRepository repository;
    // RedisTemplate:redis操作的API
    @Autowired
    private RedisTemplate redisTemplate;
    public Comment findById(int comment_id){
        //先从Redis缓存中查询数据
        Object object = redisTemplate.opsForValue().get("comment_"+comment_id);
        if(object!=null){
            return  (Comment)object;
        }else {
            //缓存中如果没有,就进入数据库查询
            Optional<Comment> optional = repository.findById(comment_id);
            if(optional.isPresent()){
                Comment comment = optional.get();
                //将查询结果进行缓存,设置有效期为1天
                redisTemplate.opsForValue().set("comment_"+comment_id,comment,1, TimeUnit.DAYS);
                return comment;
            }else {
                return null;
            }
        }
    }
    public  Comment updateComment(Comment comment){
        repository.updateComment(comment.getAuthor(),comment.getId());
        //更新数据后进行缓存更新
        redisTemplate.opsForValue().set("comment_"+comment.getId(),comment);
        return comment;
    }
    public void deleteComment(int comment_id){
        repository.deleteById(comment_id);
        //删除数据后进行缓存删除
        redisTemplate.delete("comment_"+comment_id);
    }
}
  • Redis API——RedisTemplate
    • RedisTemplate是Spring Data Redis 提供的直接进行Redis操作的Java API,可直接注入使用,更加便捷。
    • 可以操作<Object,Object>对象数据类型,其子类StringRedisTemplate是针对<String,String>型操作
    • 提供了很多进行数据缓存操作的方法
  • 编写Web访问层Controller文件
@RestController
@RequestMapping("/api") //窄化请求路径
public class ApiCommentController {
    @Autowired
    private ApiCommentService apiCommentService;
    @GetMapping("/get/{id}")
    public Comment findById(@PathVariable("id") int comment_id){
        Comment comment = apiCommentService.findById(comment_id);
        return comment;
    }

    @GetMapping("/update/{id}/{author}")
    public Comment updateComment(@PathVariable("id") int comment_id,@PathVariable("author") String author){
        Comment comment = findById(comment_id);
        comment.setAuthor(author);
        Comment updateComment = apiCommentService.updateComment(comment);
        return updateComment;
    }

    @GetMapping("/delete/{id}")
    public void deleteComment(@PathVariable("id") int comment_id){
        apiCommentService.deleteComment(comment_id);
    }
}
  • 测试如注解版测试相同
    • 基于API的Redis缓存实现不需要@EnableCaching注解开启Cache支持
    • 同样基于API的Redis缓存实现需要引入Redis依赖启动器、配置Redis服务连接、实体类序列化
    • 使用API进行数据缓存管理更加灵活。

自定义Redis缓存序列化机制

  • 对于上面两种Redis缓存整合方式,分别进行序列化设置,并自定义JSON格式的数据序列化机制进行数据缓存管理

自定义RedisTemplate

  • 基于Redis API的Redis缓存实现是使用RedisTemplate模板进行数据缓存管理的
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
	...
	// 声明了key、value的各种序列化方式,初始值为空
	 private RedisSerializer keySerializer = null;
    @Nullable
    private RedisSerializer valueSerializer = null;
    @Nullable
    private RedisSerializer hashKeySerializer = null;
    @Nullable
    private RedisSerializer hashValueSerializer = null;
    ...
    // 进行默认序列化方式设置,设置为JDK序列化方式
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        boolean defaultUsed = false;
        if (this.defaultSerializer == null) {
            this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
        }
    ...
}
  • 打开RedisTemplate类,查看源码
    • 从如下代码可以看出,如果序列号参数defaultSerializer为null,则数据序列化方式为JdkSerializationRedisSerializer
    • 1)使用RedisTemplate对Redis数据进行缓存操作时,内部使用的JdkSerializationRedisSerializer序列化方式要求被序列化的实体类继承Serializable接口
    • 2)使用RedisTemplate时,如果没有特殊设置,key和value都是使用defaultSerializer=new JdkSerializationRedisSerializer()进行序列化的。
    • 3)查看RedisSerializer类型,发现其支持的序列化方式有如下七种,默认为JdkSerializationRedisSerializer
      在这里插入图片描述
  • 自定义RedisTemplate序列化机制
    查看RedisAutoConfiguration类,核心代码如下:
	// redisTemplate组件不存在时生效
 @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
从代码中我们可以发现,如果想要使用自定义序列化的RedisTemplate进行数据缓存操作,可以创建一个名为redisTemplate的Bean组件,并在
该组件中设置对应的序列化方式即可
//新建config包
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object,Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        //使用JSON格式序列化对象,对缓存数据key和value进行转换
        Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY);
        jsonRedisSerializer.setObjectMapper(om);
        //设置RedisTemplate模板API的序列化方式为JSON
        template.setDefaultSerializer(jsonRedisSerializer);
        return template;
    }
}
  • 效果测试,发现缓存到redis的数据以JSON格式存储的,序列化成功。
    在这里插入图片描述

自定义RedisCacheManager

  • 针对基于注解的Redis缓存机制进行自动序列化
  • 查看RedisCacheConfiguration源码
    • 发现同RedisTemplate核心代码类似,其内部同样通过Redis连接工厂RedisConnectionFactory定义了一个缓存管理器RedisCacheManager;同时定制RedisCacheManager时,使用了默认的JdkSerializationRedisSerializer序列化方式
    • 如果想要使用自定义序列化方式的RedisCacheManager进行缓存操作,可以创建一个cacheManager的Bean组件。
    • (1.x的SpringBoot版本,RedisCacheManager时在RedisTemplate的基础上进行构建的)
    • (2.x的SpringBoot版本,RedisCacheManager是单独进行构建的)
class RedisCacheConfiguration {
    RedisCacheConfiguration() {
    }

    @Bean
    RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers, ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration, ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers, RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
        RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(this.determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
        List<String> cacheNames = cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            builder.initialCacheNames(new LinkedHashSet(cacheNames));
        }

        redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> {
            customizer.customize(builder);
        });
        return (RedisCacheManager)cacheManagerCustomizers.customize(builder.build());
    }
    ...
    private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(CacheProperties cacheProperties, ClassLoader classLoader) {
        Redis redisProperties = cacheProperties.getRedis();
        org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig();
        config = config.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
  • 编写自定义RedisCacheManager的Bean组件
@Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){
        //分别创建String和JSON格式化序列对象,对key和value进行转换
        RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY);
        jsonRedisSerializer.setObjectMapper(om);
        //定制换粗数据序列化方式即使生效
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                        .entryTtl(Duration.ofDays(1))
                        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer))
                        .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }
  • 测试即可,发现生效
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好,关于您的问题,可以按照以下步骤来实现springboot整合Redisidea中的操作: 1. 在pom.xml文件中添加Redis依赖 ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 在application.properties中添加Redis配置 ``` spring.redis.host=127.0.0.1 spring.redis.port=6379 ``` 3. 创建一个Redis配置类 ``` @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(objectMapper); // 设置value的序列化规则和 key的序列化规则 redisTemplate.setValueSerializer(serializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } } ``` 4. 在需要使用Redis的地方注入RedisTemplate,然后即可使用Redis的API进行操作。 ``` @Service public class UserServiceImpl implements UserService { @Autowired private RedisTemplate<String, Object> redisTemplate; @Override public User getUserById(Long id) { String key = "user_" + id; User user = (User) redisTemplate.opsForValue().get(key); if (user == null) { user = userRepository.selectById(id); if (user != null) { redisTemplate.opsForValue().set(key, user, 1, TimeUnit.MINUTES); // 缓存一分钟 } } return user; } } ``` 希望以上步骤可以帮到您,如果还有其他问题,请随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值