Springboot默认缓存+Redis缓存(使用详解)

题记

文章内容输入来源:拉勾教育Java高薪训练营
本文是Springboot课程学习中的一部分笔记。
本文详细介绍了Springboot自带的缓存使用、整合Redis实现注解式缓存与api式缓存,并配有详细的实现效果对比。

Springboot环境搭建

使用工具:idea2019.2
jdk版本:11
第一步,idea中新建项目,
Springboot默认缓存+Redis缓存(使用详解)_第1张图片导入依赖,
Springboot默认缓存+Redis缓存(使用详解)_第2张图片第二步,新建实体类Comment:

package com.lagou.pojo;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "t_comment")
public class Comment implements Serializable {
     

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String content;
    private String author;
    @Column(name = "a_id")
    private Integer aId;

    @Override
    public String toString() {
     
        return "Comment{" +
                "id=" + id +
                ", content='" + content + '\'' +
                ", author='" + author + '\'' +
                ", aId=" + aId +
                '}';
    }

    public Integer getId() {
     
        return id;
    }

    public void setId(Integer id) {
     
        this.id = id;
    }

    public String getContent() {
     
        return content;
    }

    public void setContent(String content) {
     
        this.content = content;
    }

    public String getAuthor() {
     
        return author;
    }

    public void setAuthor(String author) {
     
        this.author = author;
    }

    public Integer getaId() {
     
        return aId;
    }

    public void setaId(Integer aId) {
     
        this.aId = aId;
    }
}

第三步,使用Spring Data JPA来操作数据库:

package com.lagou.repository;

import com.lagou.pojo.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

public interface CommentRepository extends JpaRepository<Comment,Integer> {
     

    //根据评论id修改评论作者

    @Transactional
    @Modifying
    @Query(value = "update t_comment c set c.author = ?1 where  c.id=?2",nativeQuery = true)
    public int updateComment(String author, Integer id);

}

第四步,创建Service:

package com.lagou.service;

import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class CommentService {
     

    @Autowired
    private CommentRepository commentRepository;


    public Comment findCommentById(Integer id){
     
        Optional<Comment> byId = commentRepository.findById(id);
        if(byId.isPresent()){
     
            Comment comment = byId.get();
            return  comment;
        }
        return  null;
    }



}

第六步,创建controller:

package com.lagou.controller;

import com.lagou.pojo.Comment;
import com.lagou.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CommentController {
     

    @Autowired
    private CommentService commentService;


    @RequestMapping("/findCommentById")
    public Comment findCommentById(Integer id){
     
        Comment comment = commentService.findCommentById(id);
        return  comment;

    }

}

测试:
Springboot默认缓存+Redis缓存(使用详解)_第3张图片
可以看出每次执行都会查询sql,是因为没有开启缓存。

默认缓存体验

第一步,在启动类上添加注解,开启Springboot关于注解缓存的支持:

package com.lagou;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@EnableCaching
@SpringBootApplication
public class Springboot05CacheApplication {
     

    public static void main(String[] args) {
     
        SpringApplication.run(Springboot05CacheApplication.class, args);
    }

}

第二步,service上添加注解@Cacheable

package com.lagou.service;

import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class CommentService {
     

    @Autowired
    private CommentRepository commentRepository;
    
//@Cacheable:  将该方法查询结果comment存放在springboot默认缓存中//cacheNames: 起一个缓存命名空间  对应缓存唯一标识// value: 缓存结果  key:默认在只有一个参数的情况下,key值默认就是方法参数值 如果没有参数或者多个参数的情况:simpleKeyGenerate
    @Cacheable(cacheNames = "comment")
    public Comment findCommentById(Integer id){
     
        Optional<Comment> byId = commentRepository.findById(id);
        if(byId.isPresent()){
     
            Comment comment = byId.get();
            return  comment;
        }
        return  null;
    }

}

测试效果:
Springboot默认缓存+Redis缓存(使用详解)_第4张图片

Springboot整合redis实现注解缓存

spring整合redis

第一步,添加依赖

 <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

application.properties

#Redis服务连接配置
#Redis服务地址
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码
spring.redis.password=

在service中新增了两个方法,分别为更新和删除方法,并添加相应的缓存注解:

package com.lagou.service;

import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class CommentService {
     

    @Autowired
    private CommentRepository commentRepository;


    //@Cacheable:  将该方法查询结果comment存放在springboot默认缓存中
    //cacheNames: 起一个缓存命名空间  对应缓存唯一标识

    // value: 缓存结果  key:默认在只有一个参数的情况下,key值默认就是方法参数值 如果没有参数或者多个参数的情况:simpleKeyGenerate
    @Cacheable(cacheNames = "comment",unless = "#result==null")
    public Comment findCommentById(Integer id){
     
        Optional<Comment> byId = commentRepository.findById(id);
        if(byId.isPresent()){
     
            Comment comment = byId.get();
            return  comment;
        }
        return  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(Integer id){
     
        commentRepository.deleteById(id);
    }


}


在controller中新增两个方法,对于service中更新和删除操作:

package com.lagou.controller;

import com.lagou.pojo.Comment;
import com.lagou.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CommentController {
     

    @Autowired
    private CommentService commentService;

    @RequestMapping("/findCommentById")
    public Comment findCommentById(Integer id){
     
        Comment comment = commentService.findCommentById(id);
        return  comment;

    }

    @RequestMapping("/updateComment")
    public Comment updateComment(Comment comment){
     
        Comment commentById = commentService.findCommentById(comment.getId());
        commentById.setAuthor(comment.getAuthor());
        Comment comment1 = commentService.updateComment(commentById);
        return comment1;
    }

    @RequestMapping("/deleteComment")
    public void deleteComment(Integer id){
     
        commentService.deleteComment(id);
    }

}

测试:
Springboot默认缓存+Redis缓存(使用详解)_第5张图片
Springboot默认缓存+Redis缓存(使用详解)_第6张图片
Springboot默认缓存+Redis缓存(使用详解)_第7张图片

对于缓存时间的全局设置:
application.properties:

# 对基于注解的Redis缓存数据统一设置有效期为1分钟,单位毫秒
spring.cache.redis.time-to-live=60000

SpringBoot整合api实现redis缓存

新建一个service:

package com.lagou.service;

import com.lagou.pojo.Comment;
import com.lagou.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
public class ApiCommentService {
     

    @Autowired
    private CommentRepository commentRepository;

    @Autowired
    private RedisTemplate redisTemplate;


    // 使用API方式进行缓存:先去缓存中查找,缓存中有,直接返回,没有,查询数据库
    public Comment findCommentById(Integer id){
     
        Object o = redisTemplate.opsForValue().get("comment_" + id);
        if(o!=null){
     
            //查询到了数据,直接返回
            return (Comment) o;
        }else {
     
            //缓存中没有,从数据库查询
            Optional<Comment> byId = commentRepository.findById(id);
            if(byId.isPresent()){
     
                Comment comment = byId.get();
                //将查询结果存到缓存中,同时还可以设置有效期为1天
                redisTemplate.opsForValue().set("comment_" + id,comment,1, TimeUnit.DAYS);
                return  comment;
            }

        }

        return  null;
    }


    //更新方法
    public Comment updateComment(Comment comment){
     
        commentRepository.updateComment(comment.getAuthor(),comment.getId());
        //将更新数据进行缓存更新
        redisTemplate.opsForValue().set("comment_" + comment.getId(),comment);
        return comment;
    }

    //删除方法
    public void deleteComment(Integer id){
     
        commentRepository.deleteById(id);
        redisTemplate.delete("comment_" + id);
    }


}

controller基本没变:

package com.lagou.controller;

import com.lagou.pojo.Comment;
import com.lagou.service.ApiCommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api")
public class ApiCommentController {
     

    @Autowired
    private ApiCommentService commentService;


    @RequestMapping("/findCommentById")
    public Comment findCommentById(Integer id){
     
        Comment comment = commentService.findCommentById(id);
        return  comment;

    }

    @RequestMapping("/updateComment")
    public Comment updateComment(Comment comment){
     
        Comment commentById = commentService.findCommentById(comment.getId());
        commentById.setAuthor(comment.getAuthor());
        Comment comment1 = commentService.updateComment(commentById);
        return comment1;
    }

    @RequestMapping("/deleteComment")
    public void deleteComment(Integer id){
     
        commentService.deleteComment(id);
    }



}

效果:

存在的小问题:
Springboot默认缓存+Redis缓存(使用详解)_第8张图片
下面我们来进行解决。

Springboot整合redis之自定义序列化方式

定义一个Config类:

package com.lagou.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;

@Configuration
public class RedisConfig {
     

    // 自定义一个RedisTemplate

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
     
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 创建JSON格式序列化对象,对缓存数据的key和value进行转换
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);


        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(om);

        //设置redisTemplate模板API的序列化方式为json
        template.setDefaultSerializer(jackson2JsonRedisSerializer);


        return template;
    }


}

效果:
Springboot默认缓存+Redis缓存(使用详解)_第9张图片

但要注意,我们这种方式只是针对于api实现redis缓存的处理方式,而对于基于注解的redis缓存是没有作用的。
下面我们继续来实现基于注解的redis缓存的序列化实现:
在之前的RedisConfig.java中添加如下配置:


 @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
     
        // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
        RedisSerializer<String> strSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jacksonSeial =
                new Jackson2JsonRedisSerializer(Object.class);

        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);

        // 定制缓存数据序列化方式及时效
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(strSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(jacksonSeial))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager
                .builder(redisConnectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }

测试:
Springboot默认缓存+Redis缓存(使用详解)_第10张图片

写在最后

平时工作中大多是从事于crud之类的体力活,渐渐的自己也会感觉失去了前进的方向,迷茫了。自己反思了一段时间,还是自己在技术的系统性架构层面非常欠缺,没有进行过系统性的学习,说来也是缘分,正是我迷茫的那段时间,拉勾教育的Java高薪训练营课程走到了我的面前,看了下大纲之后,感觉课程内容特别丰富,有许多我的短板,于是我就果断报名了,学了一段时间,感觉超值,各位大佬老师讲的特别好,还配有每周的直播答疑,服务很好,班级里同学学习氛围也很浓厚,真庆幸自己报了名,遇见这么多优秀的人。自己给自己立个flag,一定要坚持学完,在技术上面更进一步,这就是2020年后半年的奋斗目标了。

你可能感兴趣的:(Springboot默认缓存+Redis缓存(使用详解))