SpringBoot+redis+@Cache
准备工作:
1、理解springboot缓存机制
链接:https://blog.csdn.net/SuchASilly/article/details/106102893
2、springboot整合redis的配置参考
链接:https://blog.csdn.net/SuchASilly/article/details/106103069
一、@EanblCache
这个注解要到Application启动类标明(开启缓存注解)
package com.jinv.studentinfo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@EnableCaching//启动缓存注解
@SpringBootApplication
@MapperScan("com.jinv.studentinfo.dao")/*配置MapperScan来扫描dao(Mapper)接口*/
public class StudentinfoApplication {
public static void main(String[] args) {
SpringApplication.run(StudentinfoApplication.class, args);
}
}
二、serviceImpl(service层正常写)
package com.jinv.studentinfo.service.impl;
import com.jinv.studentinfo.dao.CourseDao;
import com.jinv.studentinfo.domain.Course;
import com.jinv.studentinfo.service.CourseService;
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 org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class CourseServiceImpl implements CourseService {
@Autowired
private CourseDao courseDao;
@Override
@Cacheable(value = "course",key = "#courseId")
public Course findCourseById(String courseId) {
return courseDao.findCourseById(courseId);
}
@Override
@CachePut(value = "course",key = "#result.courseId",unless = "#result==null")
public Course updateCourse(Course course) {
courseDao.updateCourse(course);
return courseDao.findCourseById(course.getCourseId());
}
@Override
@CacheEvict(value="course",key = "#courseId")
public void deleteCourseById(String courseId) {
courseDao.deleteCourseById(courseId);
}
}
注意:这里有个坑——更新的语句,我本来写的返回值是void空,这样子就会报错
Cache ‘course’ does not allow ‘null’ values. Avoid storing null via ‘@Cacheable(unless="#result == null")’ or configure RedisCache to allow ‘null’ via RedisCacheConfiguration
原因分析:
因为@CachePut其实就是@CacheEvict和@Cacheable的联合,先清空再添加缓存达到更新效果,而且这个注解的参数就是指向返回值,所以返回值为空的话,就会找不到对应的keyvalue来执行@Cacheable
@CachePut 注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
三、web
package com.jinv.studentinfo.web;
import com.alibaba.fastjson.JSON;
import com.jinv.studentinfo.domain.Course;
import com.jinv.studentinfo.service.CourseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CourseController {
@Autowired
private CourseService courseService;
@GetMapping("/testRedis/find/{courseId}")
public String findCourse(@PathVariable String courseId){
Course course = courseService.findCourseById(courseId);
String result = JSON.toJSONString(course);
return result;
}
@GetMapping("/testRedis/update/{courseName}")
public String updateCourse(@PathVariable String courseName){
Course course = courseService.findCourseById("1");
course.setCourseName(courseName);
courseService.updateCourse(course);
return "成功!";
}
@GetMapping("/testRedis/delete/{courseId}")
public String deleteCourse(@PathVariable String courseId){
courseService.deleteCourseById(courseId);
return "萨达";
}
}
四、启动测试
1.测试@Cacheable(增)
查看redis
2.测试@CachePut(改)
redis
mysql
3.测试@CacheEvict(删)
redis
mysql
五、关于怎么才能让springboot项目不选用simpleCacheAutoConfiguration而是用Redis的Configuration
这个细节我也不清楚,应该是RedisConfig的配置使得cache的自动配置选择redis条件condition达到了就不会选择默认的,详情还是要看springboot缓存机制
总结:使用@CachePut的目标方法时update数据库的,而且必须有返回值,返回更新后的实体类