为什么使用缓存
- 对于一些经常读取很少修改的数据存入缓存,减少查询数据库的消耗
缓存的使用步骤
-
创建springboot应用,选中Mysql、Mybatis、Web模块
-
创建数据库表及对应的pojo类
@Data
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender; //性别 1男 0女
private Integer dId;
}
- 整合mybatis操作数据库
-
添加jar包依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency>
-
在application.properties中添加数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/springboot_h?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root #spring.datasource.driver-class-name=com.mysql.jdbc.Driver
-
创建dao层、service层和controller层,核心启动类上添加@MapperScan扫描mapper包
dao层:
public interface EmployeeMapper { @Select("select * from employee where id = #{id}") public Employee getEmpById(Integer id); @Insert("insert into employee(lastName, email, gender, d_id) values(#{lastName},#{email},#{gender},#{dId})") public void insertEmp(Employee employee); @Update("UPDATE employee SET lastName = #{lastName},email = #{email},gender = #{gender},d_id = #{dId} WHERE id = #{id}") public void updateEmp(Employee employee); @Delete("DELETE FROM employee WHERE id = #{id}") public void deleteEmpById(Integer id); }
service层:
@Service public class EmployeeService { @Autowired private EmployeeMapper employeeMapper; public Employee findEmpById(Integer id){ Employee emp = employeeMapper.getEmpById(id); return emp; } public Employee updateEmp(Employee employee){ employeeMapper.updateEmp(employee); return employee; public void delEmp(Integer id employeeMapper.deleteEmpById(id); } }
controller层:
@RestController public class EmployeeController { @Autowired private EmployeeService employeeService; @RequestMapping("/emp/{id}") public Employee getEmp(@PathVariable("id") Integer id){ Employee emp = employeeService.findEmpById(id); return emp; } @RequestMapping("/updateEmp/{id}") public Employee updateEmp(@PathVariable("id") Integer id){ Employee emp = employeeService.findEmpById(id); //手动设置更新 emp.setLastName("李四"); Employee employee = employeeService.updateEmp(emp); return employee; } @RequestMapping("/delEmp/{id}") public Employee delEmp(@PathVariable("id") Integer id){ employeeService.delEmp(id); return null; } }
核心启动类添加注解扫描:
@MapperScan("com.example.mapper")
-
核心启动类添加@EnableCaching开启基于注解的缓存,pojo类需要实现序列化接口
- 开启基于注解的缓存
@SpringBootApplication @MapperScan("com.example.mapper") @EnableCaching public class SpringBoot04CacheApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot04CacheApplication.class, args); } }
- 修改pojo类,实现序列化接口
@Data public class Employee implements Serializable { private Integer id; private String lastName; private String email; private Integer gender; //性别 1男 0女 private Integer dId; }
-
缓存相关注解的使用(在service层的方法上添加注解)及测试
- 查询使用:@Cacheable(key = “#id”, condition = “#id > 0”, unless = “#result == null”)
/* * @Cacheable : 缓存查询:会将该方法的返回值存到缓存中 * value/cacheNames:指定缓存的名称 ,cacheManager是管理多个cache,以名称进行区分 * key:缓存数据时指定key值 (key,value) ,默认是方法的参数值,也可以使用spEL来计算key的值 * keyGenerator:key的生成策略,和key进行二选一 ,自定义keyGenerator * cacheManager:指定缓存管理器 redis:emp ehcache:emp * cacheResolver: 功能跟cacheManager相同,二选一即可 * condition:条件属性,满足这个条件才会进行缓存 * unless: 否定条件:满足这个条件,不进行缓存 * sync: 是否使用异步模式进行缓存 true * (1) condition/unless 同时满足,不缓存 * (2) sync的值为true的时候,unless不被支持 */ @Cacheable(cacheNames = {"emp"}, key = "#id", condition = "#id > 0", unless = "#result == null") public Employee findEmpById(Integer id){ Employee emp = employeeMapper.getEmpById(id); return emp; }
先查询缓存,缓存没有则查询数据库,然后添加进缓存。
-
更新使用:@CachePut(key = “#employee.id”)
@CachePut(cacheNames = {"emp"}, key = "#employee.id") public Employee updateEmp(Employee employee){ employeeMapper.updateEmp(employee); return employee; }
方法执行,缓存也一定会更新
-
删除使用:@CacheEvict(key = “#id”,beforeInvocation = true)
//beforeInvocation = true即为在方法执行前清除缓存,为false在方法执行后再清除,若 //方法发生异常,可能产生未清除缓存的情况。 //默认为false,所以需要手动改为true @CacheEvict(cacheNames = {"emp"}, key = "#id", beforeInvocation = true) public void delEmp(Integer id){ employeeMapper.deleteEmpById(id); }
-
全局配置时使用:@CacheConfig(cacheNames = {“emp”}) ,在类上标明此注解,方法上即可省去相关配置
-
测试:
-
查询:
- 第一次查询时缓存没有数据,执行了sql语句
-
第二次查询时缓存已存入数据,不再执行sql语句
- 更新:
再次查询因为缓存已经更改,也不再执行sql语句。
- 删除:
再次查询,缓存中没有数据,所以会执行sql查询数据库,当然,数据库也没有数据了。
总结:
- 一个springboot工程想要使用缓存,在核心启动类上添加**@EnableCaching**注解即可
- @Cacheable对应查询、@Cacheput对应更新、@CacheEvict对应删除、@CacheConfig对应全局配置
- 注意pojo类需要实现序列化接口