比尔云BierYun--阿里云最新优惠活动
阿里云优惠码丨阿里云代金券

springboot集成redis

springboot集成redis

一直想在springboot上集成带缓存的redis,终于成功了。网上有1000种写法,想找到一篇合适的还真不容易😐。走下流程,加深下印象。

 环境:

springboot版本:2.1.7

orm框架:mybatis

实现🌴:

在serviceImpl层方法上加注解@Cacheable和@CachEvict。

@Cacheable把数据放进redis,下一次需要数据直接在缓存中取;@CacheEvict使redis中的缓存失效。

关于注解的更多详细可以参考https://www.cnblogs.com/fashflying/p/6908028.html写得很详细。

准备工作😬:

pom.xml🌴:

 View Code

application.properties文件🌴:

 View Code

书写😬:

一,允许使用缓存:

👉在springboot的主启动类上添加注解@EnableCaching

SbApplication.java

复制代码
 1 package com.xfk.sb;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cache.annotation.EnableCaching;
 6 
 7 @SpringBootApplication
 8 @EnableCaching
 9 public class SbApplication {
10     public static void main(String[] args) {
11         SpringApplication.run(SbApplication.class, args);
12     }
13 }
复制代码

 

 二,redis配置类:

👉这里一个重要的点就是Serializer。RedisCache默认使用的是JdkSerializationRedisSerializer,我们要实现json格式的数据在redis上的存储。利用Jackson2JsonRedisSerializer或GenericJackson2JsonRedisSerializer,其优点是存储的长度小。在这里我们用GenericJackson2JsonRedisSerializer。成功之后可以换Jackson2JsonRedisSerializer试试,看一看存储的数据有什么不同。

👉cacheManager方法是用作注解@Cacheable和@CacheEvict执行service实现层方法缓存数据的,另外就是定义一个redisTemplate,哪个controller需要就在哪个controller中注入,灵活使用。

RedisConfig.java

复制代码
 1 package com.xfk.sb.config;
 2 
 3 import org.springframework.cache.annotation.CachingConfigurerSupport;
 4 import org.springframework.cache.annotation.EnableCaching;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Configuration;
 7 import org.springframework.data.redis.cache.RedisCacheConfiguration;
 8 import org.springframework.data.redis.cache.RedisCacheManager;
 9 import org.springframework.data.redis.connection.RedisConnectionFactory;
10 import org.springframework.data.redis.core.RedisTemplate;
11 import org.springframework.data.redis.serializer.*;
12 import java.time.Duration;
13 
14 @Configuration
15 @EnableCaching
16 public class RedisConfig extends CachingConfigurerSupport {
17     // 过期时间
18     private Duration timeToLive = Duration.ofHours(12);
19 
20     @Bean
21     public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
22         RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
23                 .entryTtl(this.timeToLive)
24                 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
25                 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
26                 .disableCachingNullValues();
27 
28         return RedisCacheManager.builder(connectionFactory)
29                 .cacheDefaults(config)
30                 .transactionAware()
31                 .build();
32     }
33     
34     @Bean(name = "redisTemplate")
35     public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
36         RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
37         redisTemplate.setConnectionFactory(redisConnectionFactory);
38         redisTemplate.setKeySerializer(keySerializer());
39         redisTemplate.setHashKeySerializer(keySerializer());
40         redisTemplate.setValueSerializer(valueSerializer());
41         redisTemplate.setHashValueSerializer(valueSerializer());
42         return redisTemplate;
43     }
44 
45     private RedisSerializer<String> keySerializer() {
46         return new StringRedisSerializer();
47     }
48 
49     private RedisSerializer<Object> valueSerializer() {
50         return new GenericJackson2JsonRedisSerializer();
51     }
52 }
复制代码

三,增删改查Demo:

简单的pojo类,Student.java

 View Code

👉我使用的是mybatis的注解方式,简单的几个增删改查方法。

 

xml文件,studentMapper.xml

 View Code

 

mapper接口,StudentMapper.java

 View Code

 

service层接口,StudentService.java

 View Code

 

service实现层,StudentServiceImpl.java

复制代码
 1 package com.xfk.sb.service.implement;
 2 
 3 import com.xfk.sb.mapper.StudentMapper;
 4 import com.xfk.sb.pojo.Student;
 5 import com.xfk.sb.service.StudentService;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.cache.annotation.CacheConfig;
 8 import org.springframework.cache.annotation.CacheEvict;
 9 import org.springframework.cache.annotation.Cacheable;
10 import org.springframework.cache.annotation.Caching;
11 import org.springframework.stereotype.Service;
12 import java.util.List;
13 
14 @Service
15 @CacheConfig(cacheNames="students")
16 public class StudentServiceImpl implements StudentService {
17     private final StudentMapper studentMapper;
18 
19     @Autowired
20     public StudentServiceImpl(StudentMapper studentMapper) {
21         this.studentMapper = studentMapper;
22     }
23 
24     @Cacheable(key="'students'")
25     @Override
26     public List<Student> selectStudent() {
27         System.out.println("从数据库中取selectStudent");
28         return studentMapper.selectStudent();
29     }
30 
31     @Override
32     @Caching(evict={
33             @CacheEvict(key="'singleStudent'+#id"),
34             @CacheEvict(key="'students'"),
35     })
36     public int deleteStudent(int id) {
37         System.out.println("从数据库中删除deleteStudent");
38         return studentMapper.deleteStudent(id);
39     }
40 
41     @Override
42     @Caching(evict={
43             @CacheEvict(key="'singleStudent'+#student.id"),
44             @CacheEvict(key="'students'"),
45     })
46     public int createStudent(Student student) {
47         System.out.println("从数据库中创建createStudent");
48         return studentMapper.createStudent(student);
49     }
50 
51     @Caching(evict={
52             @CacheEvict(key="'singleStudent'+#student.id"),
53             @CacheEvict(key="'students'"),
54     })
55     @Override
56     public int updateStudent(Student student) {
57         System.out.println("从数据库中更新updateStudent");
58         return studentMapper.updateStudent(student);
59     }
60 
61     @Cacheable(key="'singleStudent'+#p0")
62     @Override
63     public Student selectStudentByPrimaryKey(int id) {
64         System.out.println("从数据库中取一个selectStudentByPrimaryKey");
65         return studentMapper.selectStudentByPrimaryKey(id);
66     }
67 }
复制代码

👉使用@CacheConfig注解,相当于在redis数据库下建一个文件夹,以cacheNames作为文件夹的名字,统一管理这个实现层缓存的数据。正如在Redis Desktop Manager下看到的目录结构,db0下有一个students文件夹。

 

👉使用@Cacheable注解使缓存生效,以实现层的selectStudentByPrimaryKey()方法为例,从数据库中根据id查询一个Student对象。

使用@Cacheable(key=”‘singleStudent’+#p0″),#p0就是形参parameter0,多个参数就是#p1,#p2,,,也可以写成#id,注意singleStudent字符串一定要用单引号扩上,然后使用字符串的拼接模式,这个变量的规则是spring的EL表达式,一定要用加上#符号,如果是一个对象则可以直接用”.”引用属性,参考createStudent()方法中的#student.id 。

属性key相当于在students文件夹下的文件夹创建一条以singleStudent+#p0为名字的一条缓存数据,在Redis Desktop Manager可以看到,由于students文件夹下的文件夹没有名字,所以成功缓存数据的命名是students::singleStudent1,两个引号之间为空。这就相当以这个命名空间下的唯一key,可以根据唯一key准确的失效缓存数据。

 

👉@CacheEvict注解使缓存失效,根据需求要保证数据库与缓存的一致性,所以操作数据库之后要同步缓存。

在更新,删除和增加后要使缓存失效,不能返回过时的信息。在这里使用@Caching的目的是使多条缓存失效,它集合了@Cacheable,@CacheEvict,@CachePut,可以很直观的管理生效与失效。还可以直接使用@CacheEvict(allEntries=true)使这个命名空间下的所有缓存失效。

到这里核心工作完成得差不多了,就还差controller返回视图层了。

 

controller层,StudentController.java

复制代码
 1 package com.xfk.sb.web;
 2 
 3 import com.xfk.sb.pojo.Student;
 4 import com.xfk.sb.service.StudentService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.data.redis.core.StringRedisTemplate;
 7 import org.springframework.stereotype.Controller;
 8 import org.springframework.ui.Model;
 9 import org.springframework.web.bind.annotation.*;
10 import java.util.List;
11 
12 @Controller
13 public class StudentController {
14     private final StudentService studentService;
15     private final StringRedisTemplate redis;
16 
17     @Autowired
18     public StudentController(StudentService studentService, StringRedisTemplate redis) {
19         this.studentService = studentService;
20         this.redis = redis;
21     }
22 
23     @GetMapping("/students")
24     public String listStudent(Model model){
25         List<Student> students = studentService.selectStudent();
26         model.addAttribute("students", students);
27         return "listStudent";
28     }
29 
30     @DeleteMapping("/students/{id}")
31     public String deleteStudent(@PathVariable("id")int id) throws Exception{
32         studentService.deleteStudent(id);
33         return "redirect:/students";
34     }
35 
36     @PutMapping("/students")
37     public String updateStudent(Student student){
38         studentService.updateStudent(student);
39         return "redirect:/students";
40     }
41     @PostMapping("/students")
42     public String createStudent(Student student){
43         studentService.createStudent(student);
44         return "redirect:/students";
45     }
46 
47     @GetMapping("/students/{id}")
48     public String editStudent(@PathVariable("id")int id, Model model){
49         Student s = studentService.selectStudentByPrimaryKey(id);
50         model.addAttribute("student", s);
51         return "editStudent";
52     }
53 
54     @RequestMapping("/test")
55     public String test(Model model){
56         List<Student> students = studentService.selectStudent();
57         model.addAttribute("students", students);
58         return "test";
59     }
60 
61     @RequestMapping("/getOne")
62     public String getOne(Model model){
       // 获取id为1的Student对象到test.jsp
63         Student student = studentService.selectStudentByPrimaryKey(1);
64         model.addAttribute("student", student);
65         return "test";
66     }
67 }
复制代码

👉使用的restful风格,返回的jsp页面,/test和/getOne用来验证缓存是否生效。

 

小贴一下jsp:

listStudent.jsp

 View Code

 

editStudent.jsp

 View Code

 

test.jsp

复制代码
 1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 2 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 3 <html>
 4 <head>
 5     <title>test</title>
 6 </head>
 7 <body>
 8 <c:forEach items="${students}" var="each">
 9     <div>${each.id}, ${each.name}, ${each.age}</div>
10 </c:forEach>
11 <br/>
12 得到一个Student<br/>
13 ${student.id}, ${student.name}, ${student.age}
14 </body>
15 </html>
复制代码

四,验证测试:

👉步骤:

1,/getOne

由于StudentServiceImpl.java中的System.out.println(“从数据库中取一个selectStudentByPrimaryKey”); 查看后台控制台,可以知道这条数据是从数据库中获取的。

/getOne获取的Student的id为1,所以会在Redis Desktop Manager中看到一条singleStudent1的缓存记录。

http://localhost:8080/getOne

2,更改Redis Desktop Manager中的记录

👉比如redis库中原来的数据是

👉更改数据,因为这里改的数据是redis的,mysql里的数据还是没变,这样就知道了是从缓存中读取的数据

👉点击save之后,刷新http://localhost:8080/getOne

成功!😆😆😆😆😆 然后@CacheEvict是一样的逻辑,指定失效的key就好了

github:https://github.com/CaseyFu/sb

参考博文:https://liuyanzhao.com/9207.html

原文地址https://www.cnblogs.com/xfk1999/p/11347793.html

未经允许不得转载:阿里云代金券 » springboot集成redis

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

强烈推荐

高性能SSD云服务器ECS抗攻击,高可用云数据库RDS