文章目录
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运行流程:
- 方法运行之前先查询Cache,按照cacheNames名称进行获取,CacheManager先获取相应组件,如果没有默认创建
ConcurrentMapCache
缓存 - Cache中查找缓存内容,使用key进行查找,key默认是方法参数
- 没有查到缓存就调用目标方法
- 目标方法返回结果,放进缓存
@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 作为缓存组件来给实际缓存中存取数据
- 引入redis的starter,容器中保存的是
RedisCacheManager
RedisCacheManager
创建RedisCache
来作为缓存组件操作redis- 默认保存数据 k-v 都是Object 利用序列化保存