一、几个重要概念&缓存注解
二、搭建基本环境
1、SpringBoot整合Mybatis操作数据库
(1)配置数据源信息
characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_cache?characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=password
# 开启驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
logging.level.com.dhu.cache.mapper=debug
(2)使用@MapperScan 指定需要扫描的mapper接口所在的包
@SpringBootApplication
@MapperScan(basePackages = "com.dhu.cache.mapper")
@EnableCaching
public class Springboot01CacheApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot01CacheApplication.class, args);
}
}
(3)
public interface EmployeeMapper {
@Select("SELECT * FROM employee WHERE id = #{id}")
Employee getEmpById(Integer id);
@Update("UPDATE employee SET lastName = #{lastName},email = #{email},gender = #{gender},d_id = #{dId} WHERE id = #{id}")
void updataEmp(Employee employee);
@Delete("DELETE FROM employee WHERE id = #{id}")
void deleteEmp(Integer id);
@Insert("INSERT INTO employee(lastName,email,gender,d_id) VALUES(#{lastName},#{email},#{gender},#{dId})")
@Options(useGeneratedKeys = true,keyProperty = "id", keyColumn = "id")
void insertEmp(Employee employee);
}
(4)
@Controller
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/emp/{id}")
@ResponseBody
public Employee getEmp(@PathVariable("id") Integer id){
Employee emp = employeeService.getEmp(id);
return emp;
}
}
三、快速使用缓存
@SpringBootApplication
@MapperScan(basePackages = "com.dhu.cache.mapper")
@EnableCaching
public class Springboot01CacheApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot01CacheApplication.class, args);
}
}
2、标注缓存注解即可
使用@Cacheable
@Service
@Slf4j
@Transactional
public class EmployeeService {
@Resource
private EmployeeMapper employeeMapper;
/**
* @Cacheable :将方法的运行结果进行缓存;以后再需要查询相同的数据,直接从缓存获取,不用调用方法
*
* CacheManager:用来管理多个Cache组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有唯一名字
* 几个属性:
* value/cacheNames:指定缓存组件的名字
* key:指定缓存数据时使用的key (缓存使用hashmap)。默认是使用方法参数的值,例如:1-方法的返回值
* 可以编写SPEL
* keyGenerator: key的生成器;可以自己指定key的生成器的组件id
* key/keyGenerator: 二选一使用
* cacheManager:指定缓存管理器
* condition:指定符合条件的情况下才缓存
* unless: 否定缓存。当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
* @param id
* @return
*/
@Cacheable(cacheNames = {"emp"},key = "#id",condition = "#id>0",unless = "#result==null") //#id 的作用是:取出参数id的值,把它作为key
public Employee getEmp(Integer id) {
System.out.println("查询" + id + "号员工...");
Employee emp = employeeMapper.getEmpById(id);
return emp;
}
}
四、缓存的使用
1、EmployeeService
查询的缓存正常
@Service
@Slf4j
@Transactional
public class EmployeeService {
@Resource
private EmployeeMapper employeeMapper;
/**
* @Cacheable :将方法的运行结果进行缓存;以后再需要查询相同的数据,直接从缓存获取,不用调用方法
*
* CacheManager:用来管理多个Cache组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有唯一名字
* 几个属性:
* value/cacheNames:指定缓存组件的名字
* key:指定缓存数据时使用的key (缓存使用hashmap)。默认是使用方法参数的值,例如:1-方法的返回值
* 可以编写SPEL
* keyGenerator: key的生成器;可以自己指定key的生成器的组件id
* key/keyGenerator: 二选一使用
* cacheManager:指定缓存管理器
* condition:指定符合条件的情况下才缓存
* unless: 否定缓存。当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
*
* 缓存工作原理:
* 1、自动配置类 : (缓存自动配置类) CacheAutoConfiguration
* 2、哪个配置类默认生效
* 运行流程:
* 1、@Cacheable标注的方法在执行之前,先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,如果没有就运行新的方法,
* 并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据
* @param id
* @return
*/
@Cacheable(cacheNames = {"emp"},key = "#root.methodName + '[' + #id + ']'",condition = "#id>0",unless = "#result==null") //#id 的作用是:取出参数id的值,把它作为key
public Employee getEmp(Integer id) {
System.out.println("查询" + id + "号员工...");
Employee emp = employeeMapper.getEmpById(id);
return emp;
}
2、Controller
@Controller
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/emp/{id}")
@ResponseBody
public Employee getEmp(@PathVariable("id") Integer id){
Employee emp = employeeService.getEmp(id);
return emp;
}
/**
* @CachePut:既调用方法,又更新缓存数据
* 也就是修改了数据库的某个数据,同时更新缓存
* 运行时机:
* 1、先调用目标方法
* 2、将目标方法的结果缓存起来
* 测试:
* 1、查询1号员工;查到的结果会放在缓存中
* 2、以后查询还是之前的结果
* 3、更新1号员工
* 4、再次查询1号员工?
* 应该是更新后的员工;可是为什么查询出来的是没更新前的?
*/
@CachePut(value = "{emp")
public Employee updateEmp(Employee employee){
System.out.println("update --- " + employee);
employeeMapper.updataEmp(employee);
return employee;
}
4、使用更新操作与缓存
@ResponseBody
@GetMapping("/emp")
public Employee update(Employee employee){
employeeService.updateEmp(employee);
return employee;
}
5、存在问题
6、解决
/**
* @CachePut:既调用方法,又更新缓存数据
* 也就是修改了数据库的某个数据,同时更新缓存
* 运行时机:
* 1、先调用目标方法
* 2、将目标方法的结果缓存起来
* 测试:
* 1、查询1号员工;查到的结果会放在缓存中
* key:1 value:lastName:李四
* 2、以后查询还是之前的结果
* 3、更新1号员工:
* 将方法的返回值也放进缓存
* key:employee(默认是使用方法参数的值) value:返回的employee对象
* 4、再次查询1号员工?
* 应该是更新后的员工;
* 可是为什么查询出来的是没更新前的?【1号员工没有在缓存中更新】
* 解决方法:
* 使用key = "#employee.id":使用传入员工参数对象的id;
* 或者key = "#result.id"
*/
@CachePut(value = {"emp"},key = "#employee.id")
public Employee updateEmp(Employee employee){
System.out.println("update --- " + employee);
employeeMapper.updataEmp(employee);
return employee;
}