• Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
  • 1、安装redis:使用docker;
  • 2、引入redis的starter
  • 3、配置redis
  • 4、测试缓存
  • 原理:CacheManager===Cache 缓存组件来实际给缓存中存取数据*1)、引入redis的starter,容器中保存的是 RedisCacheManager; *3)、默认保存数据 k-v 都是Object;利用序列化保存;如何保存为json
  • 1、引入了redis的starter,cacheManager变为 RedisCacheManager;
  • 2、默认创建的 RedisCacheManager 操作redis的时候使用的是 RedisTemplate<Object, Object>
  • 3、RedisTemplate<Object, Object> 是 默认使用jdk的序列化机制
  • 4)、自定义CacheManager;* */
  • 步骤:
  • 1、在主程序使用注解@MapperScan("包名"),扫描基于注解实现的crud接口等等。
  • 要使用缓存就得在主程序开启注解@EnableCaching
  • 2、编写好增删改查的实现类,在service层的接口实现类使用注解@Cacheable(value="{emp}",key=)
    @CacheConfig(cacheNames="emp"/,cacheManager = "employeeCacheManager"/) //抽取缓存的公共配置@Servicepublic class EmployeeService {
  • @AutowiredEmployeeMapper employeeMapper;
• 
/**
 * 将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法;
 * CacheManager管理多个Cache组件的,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字;
 *

 *
 * 原理:
 *   1、自动配置类;CacheAutoConfiguration
 *   2、缓存的配置类
 *   org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration
 *   org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】
 *   org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
 *   3、哪个配置类默认生效:SimpleCacheConfiguration;
 *
 *   4、给容器中注册了一个CacheManager:ConcurrentMapCacheManager
 *   5、可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中;
 *
 *   运行流程:
 *   @Cacheable:
 *   1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
 *      (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
 *   2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
 *      key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
 *          SimpleKeyGenerator生成key的默认策略;
 *                  如果没有参数;key=new SimpleKey();
 *                  如果有一个参数:key=参数的值
 *                  如果有多个参数:key=new SimpleKey(params);
 *   3、没有查到缓存就调用目标方法;
 *   4、将目标方法返回的结果,放进缓存中
 *
 *   @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
 *   如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;
 *
 *   核心:
 *      1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
 *      2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator
 *
 *
 *   几个属性:
 *      cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
 *
 *      key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值
 *              编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]
 *              getEmp[2]
 *
 *      keyGenerator:key的生成器;可以自己指定key的生成器的组件id
 *              key/keyGenerator:二选一使用;
 *
 *
 *      cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
 *
 *      condition:指定符合条件的情况下才缓存;
 *              ,condition = "#id>0"
 *          condition = "#a0>1":第一个参数的值》1的时候才进行缓存
 *
 *      unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
 *              unless = "#result == null"
 *              unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
 *      sync:是否使用异步模式
 * @param id
 * @return
 *
 */
@Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/)
public Employee getEmp(Integer id){
    System.out.println("查询"+id+"号员工");
    Employee emp = employeeMapper.getEmpById(id);
    return emp;
}

/**
 * @CachePut:既调用方法,又更新缓存数据;同步更新缓存
 * 修改了数据库的某个数据,同时更新缓存;
 * 运行时机:
 *  1、先调用目标方法
 *  2、将目标方法的结果缓存起来
 *
 * 测试步骤:
 *  1、查询1号员工;查到的结果会放在缓存中;
 *          key:1  value:lastName:张三
 *  2、以后查询还是之前的结果
 *  3、更新1号员工;【lastName:zhangsan;gender:0】
 *          将方法的返回值也放进缓存了;
 *          key:传入的employee对象  值:返回的employee对象;
 *  4、查询1号员工?
 *      应该是更新后的员工;
 *          key = "#employee.id":使用传入的参数的员工id;
 *          key = "#result.id":使用返回后的id
 *             @Cacheable的key是不能用#result
 *      为什么是没更新前的?【1号员工没有在缓存中更新】
 *
 */
@CachePut(/*value = "emp",*/key = "#result.id")
public Employee updateEmp(Employee employee){
    System.out.println("updateEmp:"+employee);
    employeeMapper.updateEmp(employee);
    return employee;
}

/**
 * @CacheEvict:缓存清除
 *  key:指定要清除的数据
 *  allEntries = true:指定清除这个缓存中所有的数据
 *  beforeInvocation = false:缓存的清除是否在方法之前执行
 *      默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
 *
 *  beforeInvocation = true:
 *      代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
 *
 *
 */
@CacheEvict(value="emp",beforeInvocation = true/*key = "#id",*/)
public void deleteEmp(Integer id){
    System.out.println("deleteEmp:"+id);
    //employeeMapper.deleteEmpById(id);
    int i = 10/0;
}

// @Caching 定义复杂的缓存规则
@Caching(
     cacheable = {
         @Cacheable(/*value="emp",*/key = "#lastName")
     },
     put = {
         @CachePut(/*value="emp",*/key = "#result.id"),
         @CachePut(/*value="emp",*/key = "#result.email")
     }
)
public Employee getEmpByLastName(String lastName){
    return employeeMapper.getEmpByLastName(lastName);
}
  • 使用redis

  • 导入redis环境
• <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>• @Configurationpublic class MyRedisConfig {
• @Bean
public RedisTemplate<Object, Employee> empRedisTemplate(
        RedisConnectionFactory redisConnectionFactory)
        throws UnknownHostException {
    RedisTemplate<Object, Employee> template = new RedisTemplate<Object, Employee>();
    template.setConnectionFactory(redisConnectionFactory);
    Jackson2JsonRedisSerializer<Employee> ser = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
    template.setDefaultSerializer(ser);
    return template;
}
@Bean
public RedisTemplate<Object, Department> deptRedisTemplate(
        RedisConnectionFactory redisConnectionFactory)
        throws UnknownHostException {
    RedisTemplate<Object, Department> template = new RedisTemplate<Object, Department>();
    template.setConnectionFactory(redisConnectionFactory);
    Jackson2JsonRedisSerializer<Department> ser = new Jackson2JsonRedisSerializer<Department>(Department.class);
    template.setDefaultSerializer(ser);
    return template;
}• //CacheManagerCustomizers可以来定制缓存的一些规则
@Primary  //将某个缓存管理器作为默认的
@Bean
public RedisCacheManager employeeCacheManager(RedisTemplate<Object, Employee> empRedisTemplate){
    RedisCacheManager cacheManager = new RedisCacheManager(empRedisTemplate);
    //key多了一个前缀

    //使用前缀,默认会将CacheName作为key的前缀
    cacheManager.setUsePrefix(true);

    return cacheManager;
}

@Bean
public RedisCacheManager deptCacheManager(RedisTemplate<Object, Department> deptRedisTemplate){
    RedisCacheManager cacheManager = new RedisCacheManager(deptRedisTemplate);
    //key多了一个前缀

    //使用前缀,默认会将CacheName作为key的前缀
    cacheManager.setUsePrefix(true);

    return cacheManager;
}