SpringBoot Cache学习

Cache

1.创建SpringBoot项目

在这里插入图片描述

配置文件

spring:
  datasource:
    password: root.123
    username: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/library?useSSL=false

对象

public class Books {
    private Integer bookId;
    private String bookName;
    private Double bookPrice;
    private Date bookDate;
}

数据库

在这里插入图片描述

BooksMapper

注意@Results要加在SELECT语句上

@Mapper
public interface BooksMapper {
    int deleteByPrimaryKey(Integer bookId);
    
    @Insert("insert into books values(#{bookId},#{bookName},#{bookPrice},#{bookDate})")
    @ResultMap(value = "bookMap")
    int insert(Books record);

    @Select("select * from books where book_id = #{bookId}")
    @Results(id = "bookMap",value = {
            @Result(id = true,column = "book_id",property = "bookId",jdbcType = JdbcType.INTEGER),
            @Result(column = "book_name",property = "bookName",jdbcType = JdbcType.VARCHAR),
            @Result(column = "book_date",property = "bookDate",jdbcType = JdbcType.DATE),
            @Result(column = "book_price",property = "bookPrice",jdbcType = JdbcType.DOUBLE)
    })
    Books selectById(Integer bookId);

    @Select("select * from books")
    @ResultMap(value = "bookMap")
    List<Books> selectAll();

    @Update("UPDATE `library`.`books` SET `book_name` = 'Java编程思想', `book_price` = 98.5, `book_date` = '2006-01-02' WHERE `book_id` = 1")
    int updateByPrimaryKey(Books record);
}

SpringBoot使用驼峰命名可以省略@Results的书写,SpringBoot2.0版本不用写直接转换

mybatis:
  configuration:
    map-underscore-to-camel-case: true

BooksController

注意:@RequestMapping("/books/{id}"),如果写成#{id}会出现错误Invocation of init method failed; nested exception is java.lang.IllegalStateException: Invalid mapping on handler class 无效映射异常

@RestController
public class BooksController {

    @Autowired
    BooksService booksService;

    @RequestMapping("/books/{id}")
    public Books getBooks(@PathVariable("id") Integer id){
        Books books = booksService.selectBookById(id);
        return books;
    }
}

2. 使用缓存

使用缓存中的注解

注解功能
@EnableCaching开启基于注解的缓存
@Cacheable针对方法进行配置,根据方法的请求参数对其结果进行缓存
@CacheEvict清空缓存
@CachePut保证方法被调用,又希望结果被缓存

打印mapper下的操作日志

#打印查询日志
logging:
  level:
    myself.cache.mapper : debug

在这里插入图片描述
每次访问都从数据库中读取,进行一次数据库访问

@Cacheable

Service类的方法上加@Cacheable表示对该方法的返回进行缓存操作,使用之后可以发现,刷新页面查询相同内容,没有在出现查询数据库的日志

/**
 * 将方法的运行结果进行缓存,以后再使用相同数据不用调用方法
 *  * CacheManager管理多个Cache组件,对缓存真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一的名字
 * 属性:
 *      cacheNames/value:指定名字,将缓存值放进哪几个缓存中,可以是多个值
 *      key:缓存数据使用的key键值,进行指定,默认使用方法参数的值
 *          spEL语法命名  参数id的值,#id #a0 #p0 #root.args[0]
 *      keyGenerator:key的生成器,可以自己制定key的生成器组件
 *          key/keyGenerator二选一
 *      cacheManager:指定缓存管理器
 *          或者使用cacheResolver缓存解析器
 *          (redis/concurrentHashMap)
 *      condition:指定符合条件下才能缓存,#id>1 id大于1才进行缓存
 *      unless:否定缓存,当unless指定的条件为true,方法返回值不会被缓存
 *      sync:缓存是否使用异步模式
 *  *  * @param id
 * @return
 */
@Cacheable(cacheNames = "books")
public Books selectBookById(Integer id){
    System.out.println("查询" + id +"号书籍");
    Books book = booksMapper.selectById(1);
    return book;
}

key的书写方式
在这里插入图片描述

@Cacheable不起作用原因
  • application.cache.type = redis application.yml启用
  • 缓存对象实现Serializable
  • SpringBootApplication中加@EnableCaching注解
    在这里插入图片描述
  • @Cacheable基于Spring AOP实现,内部方法调用不走代理,不起作用
原理-运行流程

自动配置类CacheAutoConfiguration,对各种缓存进行自动配置

在这里插入图片描述
@Cacheable运行流程:

  1. 方法运行之前先查询Cache,按照cacheNames名称进行获取,CacheManager先获取相应组件,如果没有默认创建ConcurrentMapCache缓存
  2. Cache中查找缓存内容,使用key进行查找,key默认是方法参数
  3. 没有查到缓存就调用目标方法
  4. 目标方法返回结果,放进缓存

@CachePut

既调用方法,有更新缓存数据,场景例如:修改了数据库中的某个值,同时更新缓存。

使用@CachePut注解先调用目标方法,将查到的数据放进缓存,但是调用查看方法还是会查询数据库,因为key没有谁定,两条相同数据的key不同,一个是id一个是对象,所以需要设定key值@CachePut(cacheNames = "books" key=“#result.bookId”)

key的设定方法
#employee.id 传入的参数的id
#result.id 返回值的id (@Cacheable不能使用这种方法,流程不同)

/**
 * 运行时机:先调用目标方法,将目标方法缓存起来
 * @param book
 * @return
 */
@CachePut(cacheNames = "books")
public Books updateBooks(Books book){
    int i = booksMapper.updateByPrimaryKey(book);
    System.out.println("被更新的行: "+i);
    return book;
}

@CacheEvict

/**
 * @CacheEvict: 缓存清楚
 *      key:指定要清楚的数据
 *      allEntries = true:指定清除这个缓存中所有的数据
 *      beforeInvocation = false:缓存清除是否在方法之前执行
 *          默认缓存清除在方法执行之后
 * @param id
 * @return
 */
@Caching
@CacheEvict(cacheNames = "books",key = "#id")
public String delete(Integer id){
    booksMapper.deleteByPrimaryKey(id);
    System.out.println("delete"+id);
    return "删除"+id+"号书成功";
}

@CacheConfig

抽取缓存的公共配置,例如cacheNames

3. Redis配置

pom.xml配置,spring-boot-starter-data-redis注意增加了data

<!--redis-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
@SpringBootTest
public class TestRedis {
    //操作字符串更多,单独列出字符串,k-v都是字符串
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    //k-v均可操作,都是对象
    @Autowired
    RedisTemplate redisTemplate;
}

使用不同的方法对不同的数据结构进行操作

stringRedisTemplate.opsForValue()
stringRedisTemplate.opsForList()
stringRedisTemplate.opsForSet()
stringRedisTemplate.opsForHash()
stringRedisTemplate.opsForZSet()

Redis操作

//String类型创建和获取
stringRedisTemplate.opsForValue().set("name","zhangsan");
String name = stringRedisTemplate.opsForValue().get("name");
System.out.println(name);

自定义RedisTemplate

直接存入对象类型数据会存入字节格式,要想存入JSON格式保证可读性,可以自己编写RedisConfig文件,设置template的序列化方式。
这里使用的是RedisTemplate所以输出不是String类型

//string: object
Books book1 = new Books(1, "Java并发编程之美", 55.5, new Date());
redisTemplate.opsForValue().set("book1",book1);

在这里插入图片描述
自定义RedisConfig RedisTemplate

@Configuration
public class redisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //配置连接工厂
        template.setConnectionFactory(redisConnectionFactory);

        //使用json序列化器
        Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        //设置默认序列化器
        template.setDefaultSerializer(jsonRedisSerializer);
        //设置value序列化器
        template.setValueSerializer(jsonRedisSerializer);
        //设置key序列化器
        template.setKeySerializer(jsonRedisSerializer);
        return template;
    }
}

在这里插入图片描述

缓存管理CacheManager

原理:CacheManager 作为缓存组件来给实际缓存中存取数据

  1. 引入redis的starter,容器中保存的是RedisCacheManager
  2. RedisCacheManager创建RedisCache来作为缓存组件操作redis
  3. 默认保存数据 k-v 都是Object 利用序列化保存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值