Springboot缓存的使用

  • 什么是缓存
  • spring缓存是什么
  • spring中缓存的注解
  • @EnableCaching
  • @Cacheable
  • @CachePut
  • @CacheEvict
  • @CacheConfig
  • 总结


什么是缓存

缓存是为了解决CPU速度和内存速度的速度差异问题。内存中被CPU访问最频繁的数据和指令被复制入CPU中的缓存,这样CPU就可以不经常到象“蜗牛”一样慢的内存中去取数据了,CPU只要到缓存中去取就行了,而缓存的速度要比内存快很多。

spring缓存是什么

反正也就一个道理,存储一些我们经常要用的的数据
减轻数据库的压力

spring中缓存的注解

@EnableCaching

  1. 是什么
    开启基于注解的缓存
  2. 怎么用
    标注在方法类中
@EnableCaching//开启缓存注解
public class BookService {
}

@Cacheable

  1. 是什么
    当第一次访问的时候,把结果返回给用户,并把结果数据存到缓存中,下次访问不经过方法,直接返回缓存中的数据,一般用作查找
  2. 参数有什么

key

作用

cacheNames/value

表示缓存组件的名字

key/keyGenerator

表示存储到缓存的键名,可以用spel表达式/key的生成策略

cacheManager/cacheResolver

指定用什么做管理器,管理多个组件,比如用redis的缓存,或者自带的默认的concurrenthashmap

condition

条件成功缓存,可以用spel表达式

unless

条件成功不缓存,可以用spel表达式

3,举例子
实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    Long bookId;
    String bookName;
}

service层(用静态代码块不连接数据库了 方便一点。。。)

@Component
@EnableCaching//开启缓存注解
public class BookService {


    public static HashMap<Long, Book> map = new HashMap<>();
    static {
        map.put(1L,new Book(1L,"老人与海"));
        map.put(2L,new Book(2L,"海的女儿"));
        map.put(3L,new Book(3L,"红高粱"));
    }
    @Cacheable(value = "book",key = "#id")
    public Book getBookById(Long id){
        Book book = map.get(id);
        System.out.println(book);
        return map.get(id);
    }
}

控制层

@RestController
public class BookController {

    @Autowired
    BookService bookService;
    @GetMapping("/get")
    public Book getByBookId(Long id){
        return bookService.getBookById(id);
    }
}

开机启动

第一次访问

springboot 集成jredis 批量删除缓存_spring


清空控制台第二次访问

springboot 集成jredis 批量删除缓存_缓存_02


没有任何打印,说明缓存成功了?

那么它存储到哪里去了

经过调试

在CacheConfigurations中有这么一段代码存放着缓存配置

static {
        Map<CacheType, Class<?>> mappings = new EnumMap(CacheType.class);
        mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class);
        mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class);
        mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class);
        mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class);
        mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class);
        mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class);
        mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
        mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
        mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class);
        mappings.put(CacheType.NONE, NoOpCacheConfiguration.class);
        MAPPINGS = Collections.unmodifiableMap(mappings);
    }

默认实现的就是
SimpleCacheConfiguration.class的配置
而这个配置类中有这么一段bean

@Bean
    ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers) {
        ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
        List<String> cacheNames = cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            cacheManager.setCacheNames(cacheNames);
        }

        return (ConcurrentMapCacheManager)cacheManagerCustomizers.customize(cacheManager);
    }

在点进去一看发现存储的就是用concurrenthasp
难怪我之前实习的时候项目经理说你用缓存干嘛不自己写一个hashmap!!!

@CachePut

  1. 是什么
    当第一次访问的时候,把结果返回给用户,并把结果数据存到缓存中,下次还访问方法,并重新设置缓存中的数据简单来说就是每次执行方法每次存数据!一般用作更新
  2. 注解参数
    同@CachePut一样
  3. 测试
    service
@CachePut(value = "book",key = "#a0.bookId")//#a0代表参数中第一个参数的bookId作为key
    public Book updateBook(Book book){
        System.out.println("要修改的书本数据:"+book);
        map.put(book.getBookId(),book);
        return map.get(book.getBookId());
    }

控制层

@GetMapping("/update")
    public Book updateBook(Book book){
        Book book1 = bookService.updateBook(book);
        return book1;
    }

开机启动

查询数据

springboot 集成jredis 批量删除缓存_缓存_03


更新数据

springboot 集成jredis 批量删除缓存_java_04


在查询一次数据

springboot 集成jredis 批量删除缓存_缓存_05


数据改了,而且没在访问查询的代码而是直接访问缓存了(注意,缓存的key一定要一样根据id来)

@CacheEvict

  1. 是什么
    根据key删除缓存一般用作删除
  2. 注解参数
    同@CachePut一样
    但是多了2个

key

作用

allEntries

是否需要清除管理器缓存中的所有元素默认为false

beforeInvocation

是否在方法前删除缓存默认false

  1. 测试
    service
@CacheEvict(value = "book",key = "#id")
    public void delete(Long id){
        System.out.println("删除缓存:"+id);
    }

控制层

@GetMapping("/delete")
    public String deleteBook(Long id){
        bookService.delete(id);
        return "删除成功";
    }

启动

先查询id=1

springboot 集成jredis 批量删除缓存_缓存_06


这时候缓存了key=1的缓存,这时候我们删除缓存

springboot 集成jredis 批量删除缓存_java_07


我们在查询一下id=1

springboot 集成jredis 批量删除缓存_java_08


这时候发现缓存没了,执行方法里面

结束!

4. 测试(beforeInvocation)

service

@CacheEvict(value = "book",key = "#id",beforeInvocation = true)
    public void delete(Long id){
        System.out.println("删除缓存:"+id);
        int a = 10/0;
        map.remove(id);
    }

控制层

@GetMapping("/delete")
    public String deleteBook(Long id){
        bookService.delete(id);
        return "删除成功";
    }

启动

先查询id=1

springboot 集成jredis 批量删除缓存_spring_09


删除

springboot 集成jredis 批量删除缓存_java_10


我故意写个异常在里面,看看方法执行前有没有删除缓存

在执行查询

springboot 集成jredis 批量删除缓存_spring_11


有执行方法体的内容了,说明在执行删除前已经删除缓存了!

在缓存后删除可以自行测试

还有那个allEntries 也可以自行测试

@CacheConfig

  1. 是什么
    标注在类上,表面这个类所有方法的缓存的一些属性是都是这个
  2. 参数

key

作用

cacheNames

表示缓存组件的名字

keyGenerator

表面key的生成策略

cacheManager/cacheResolver

总结

这可能只是基本的使用
后续当我们用redis等中间件做缓存
根据spring规则注入使用
切忌!缓存最好不要乱用!!