本章给大家带来的是SpringBoot和缓存的学习。同时已经录制了非常详细的视频,如果看文档较为吃力,可以结合视频进行学习,帮你快速掌握SringBoot与缓存。
一、JSR107
Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。
- CachingProvider 定义了创建、配置、获取、管理和控制多个 CacheManager 。一个应用可以在运行期访问多个 CachingProvider 。
- CacheManager 定义了创建、配置、获取、管理和控制多个唯一命名的 Cache ,这些 Cache 存在于 CacheManager 的上下文中。一个 CacheManager 仅被一个 CachingProvider 所拥有。
- Cache 是一个类似 Map 的数据结构并临时存储以 Key 为索引的值。一个 Cache 仅被一个 CacheManager 所拥有。
- Entry 是一个存储在 Cache 中的 key-value 对。
- Expiry 每一个存储在 Cache 中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过 ExpiryPolicy 设置。
二、Spring缓存抽象
Spring从3.1开始定义了org.springframework.cache.Cache
和org.springframework.cache.CacheManager接口来统一不同的缓存技术;
并支持使用JCache(JSR-107)注解简化我们的开发;
- Cache 接口为缓存的组件规范定义,包含缓存的各种操作集合;
- Cache 接口下 Spring 提供了各种 xxxCache 的实现;如 RedisCache , EhCacheCache , ConcurrentMapCache 等;
- 每次调用需要缓存功能的方法时, Spring 会检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。
- 使用 Spring 缓存抽象时我们需要关注以下两点;
1、确定方法需要被缓存以及它们的缓存策略
2、从缓存中读取之前缓存存储的数据
三、几个重要概念&缓存注解
SpEL语法的缓存格式
四、缓存使用
• 1 、引入 spring-boot-starter-cache 模块
• 2 、 @ EnableCaching 开启缓存
• 3 、使用缓存注解
• 4 、切换为其他缓存
测试缓存对象:
五、整合redis实现缓存
- 引入 spring-boot-starter-data- redis 、 spring-data- redis
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
- 配置redis连接地址spring.redis.host=192.168.0.108
- 使用ReditTemplate操作redis
1. redisTemplate.opsForValue ();// 操作字符串
2. redisTemplate.opsForHash ();// 操作 hash
3. redisTemplate.opsForList ();// 操作 list
4. redisTemplate.opsForSet ();// 操作 set
5. redisTemplate.opsForZSet ();// 操作有序 set
redisconfig实现:
@Configuration public class RedisConfig { //过期时间 private Duration timeToLive = Duration.ofDays(1); @Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory){ RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(timeToLive) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer())) .disableCachingNullValues(); RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory) .cacheDefaults(configuration).transactionAware().build(); return redisCacheManager; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); template.setKeySerializer(keySerializer()); template.setHashKeySerializer(keySerializer()); template.setValueSerializer(valueSerializer()); template.setHashValueSerializer(valueSerializer()); return template; } private RedisSerializer<String> keySerializer(){ return new StringRedisSerializer(); } private RedisSerializer<Object> valueSerializer(){ return new GenericJackson2JsonRedisSerializer(); } }
application.properties的配置:
spring.datasource.username=spring spring.datasource.password=spring #开启驼峰命名匹配规则 mybatis.configuration.map-underscore-to-camel-case=true logging.level.com.dahaiwuliang.cache.mapper=debug #redis连接 spring.redis.host=192.168.0.108
六、整合一个实例
* Cacheable的运行流程 * 1、在方法运行之前,先去缓存按value查找Cache,第一次获取不到就会创建 * 2、去Cache中查找Entry,使用一个key,默认用方法的参数 * key是按某种规则创建的,默认是使用的SimpleKeyGenerator生成 * SimpleKeyGenerator的生成策略: * 如果没有参数,key=new SimpleKey(); * 如果有一个参数,key=参数的值 * 如果有多个参数:key=new SimpleKey(params); * * 3、如果查到,直接返回;没有查到就调用目标方法 * 4、将目标方法返回的结果放到缓存里面 * * cacheNames/value: * 指定缓存组件(Cache)的名字,将方法的返回结果放到哪个缓存中,是数组的方式,可以指定多个缓存 * * key: * Entry里面的key,默认是使用的SimpleKeyGenerator生成; * 也可以写SpEL表达式来生成 #a0 #p0 #root.args[0] #id * keyGenerator:key的生成器,可以自定义一个 * * cacheManager:指定缓存管理器 * * condition:指定符合条件的情况下才缓存 * * unless:否定缓存,和condition正好相反 * * sync:是否使用异步模式
controller层:
@RestController public class EmployeeController { @Autowired EmployeeService employeeService; @GetMapping("/getEmployee") public Employee getEmployee(Integer id){ Employee employee = employeeService.getEmp(id); return employee; } @GetMapping("/updateEmployee") public Employee update(Employee employee){ Employee emp = employeeService.updateEmp(employee); return emp; } @GetMapping("/deleteEmployee") public String deleteEmp(Integer id){ employeeService.deleteEmp(id); return "success"; } @GetMapping("/emp/{lastName}") public Employee getEmployeeByLastName(@PathVariable("lastName") String lastName){ return employeeService.getEmployeeByLastName(lastName); } }
service层:
public Employee getEmp(Integer id){ System.out.println("查询"+id+"员工"); Employee employee = employeeMapper.getEmpById(id); Cache cache = cacheManager.getCache("emp"); cache.put("emp:"+id,employee); return employee; } /** * @CachePut:既调用方法,又更新缓存 * 修改了数据库的数据,并同时更新缓存 * 运行机制: * 1、先调用目标方法; * 2、将目标方法的结果缓存起来 */ @CachePut(/*value = "emp",*/key="#result.id") public Employee updateEmp(Employee employee){ System.out.println("update:"+employee); employeeMapper.updateEmp(employee); return employee; } /** * @CacheEvict:清除缓存 * allEntries=true清空这个缓存中的所有数据 * beforeInvocation=true代表清空缓存操作是在方法执行前就执行了,无论方法是否出现异常,缓存都会被清除 */ @CacheEvict(/*value = "emp",*/key = "#id"/*,allEntries = true*/,beforeInvocation = true) public void deleteEmp(Integer id){ System.out.println("deletEmp:"+id); //employeeMapper.deleteEmpById(id); int a = 10/0; } /** * @Caching 定义复杂的缓存规则 */ @Caching( cacheable = { @Cacheable(/*value = "emp",*/key = "#lastName") }, put = { @CachePut(/*value = "emp",*/key = "#result.id") } ) public Employee getEmployeeByLastName(String lastName){ System.out.println("getEmployeeByLastName:"+lastName); return employeeMapper.getEmpByLastName(lastName); } }