Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们的开发。
创建项目
导入数据库文件
/*
Navicat MySQL Data Transfer
Source Server : 本地
Source Server Version : 50528
Source Host : 127.0.0.1:3306
Source Database : springboot_cache
Target Server Type : MYSQL
Target Server Version : 50528
File Encoding : 65001
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`departmentName` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for employee
-- ----------------------------
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`lastName` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`gender` int(2) DEFAULT NULL,
`d_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
整合Mybatis操作数据库
spring:
datasource:
url: jdbc:mysql://localhost:3306/spring_cache?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: XHHP0913
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
configuration:
map-underscore-to-camel-case: true
package com.crud.springboot.mapper;
import com.crud.springboot.bean.Employee;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
public void updateEmp(Employee employee);
public void deleteEmpById(Integer id);
public void insertUser(Employee employee);
public Employee getEmpByLastName(String lastName);
}
<mapper namespace="com.crud.springboot.mapper.EmployeeMapper">
<select id="getEmpById" resultType="com.crud.springboot.bean.Employee">
select * from employee where id=#{id}
select>
<update id="updateEmp">
update employee set lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} where id=#{id}
update>
<delete id="deleteEmpById">
delete from employee where id=#{id}
delete>
<insert id="insertUser">
insert into employee(lastName,email,gender,d_id) values(#{lastName},#{email},#{gender},,#{dId})
insert>
<select id="getEmpByLastName" resultType="com.crud.springboot.bean.Employee">
select * from employee where lastName=#{lastName}
select>
mapper>
开启基于注解的缓存
@MapperScan("com.crud.springboot.mapper")
@SpringBootApplication
@EnableCaching
public class Springboot01CacheApplication
标注缓存注解即可
@Cacheable(cacheNames = {"emp","temp"})
public Employee getEmp(Integer id){
System.out.println("查询2号员工");
Employee emp = employeeMapper.getEmpById(id);
return emp;
}
备注:
1. 将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法;
2.CacheMananger管理多个Cache组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件都有自己唯一一个名字
3.@Cacheable有如下几个可配置属性
属性 | 配置内容 |
---|---|
cacheNames/value | 指定缓存的名字 |
key | 缓存数据时使用的key;可以用它来指定。默认是使用方法参数的值 |
keyGenerator | key的生成器:可以自己指定key的生成器的组件id |
cacheMananger | 指定缓存管理器;或者cacheResolver指定缓存解析器 |
condition | 指定符合条件的情况下才缓存 |
unless | 否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断 |
sync | 是否使用异步模式 |
备注 | key/keyGenerator 二选一使用、cacheMananger/cacheResolver 二选一使用 |
@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 在方法执行之前清空缓存(默认是false)
* @param id
*/
@CacheEvict(cacheNames = {"emp"},key = "#id")
public void deleteEmp(Integer id){
System.out.println("deleteEmp:"+id);
employeeMapper.deleteEmpById(id);
}
@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){
Employee emp = employeeMapper.getEmpByLastName(lastName);
return emp;
}
@Service
@CacheConfig(cacheNames = "emp")
public class EmployeeService {
SpringBoot默认使用的是ConcurrentMapCacheManager=ConcurrentMapCache;
开发中使用缓存中间件:redis、memcached、ehcache;
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
spring:
datasource:
redis:
host: 192.168.56.102
原理: CacheManager==Cache 缓存组件来实际给缓存中存取数据
引入redis的starter,容器中保存的是RedisCacheManager
RedisCacheManager 帮我们创建RedisCache来作为缓存组件
RedisCache通过操作Redis来缓存数据
默认保存数据 k-v 都是通过Object;利用序列化保存;如何保存为json:
1、引入了redis的starter,cacheManager变为RedisCacheManager;
2、默认创建的CacheManager操作Redis的时候使用的是RedisTemplate
自定义CacheManager:
/**
* 2.0版本RedisCacheManager
* @param redisConnectionFactory
* @param empRedisTemplate
* @return
*/
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){
//初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
//设置CacheManager的值序列化方式为json序列化
RedisSerializer<Employee> jsonSerializer = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
RedisSerializationContext.SerializationPair<Employee> pair = RedisSerializationContext.SerializationPair
.fromSerializer(jsonSerializer);
RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(pair);
//初始化RedisCacheManager
return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
}
需要为不同方法指定对应的CacheManager,并且要选择一个Primary的CacheManager
@Primary
@Bean
public RedisCacheManager deptRedisCacheManager(RedisConnectionFactory redisConnectionFactory){
//初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
//设置CacheManager的值序列化方式为json序列化
RedisSerializer<Department> jsonSerializer = new Jackson2JsonRedisSerializer<Department>(Department.class);
RedisSerializationContext.SerializationPair<Department> pair = RedisSerializationContext.SerializationPair
.fromSerializer(jsonSerializer);
RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(pair);
//初始化RedisCacheManager
return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
}
@Cacheable(cacheNames = "dept",cacheManager = "deptRedisCacheManager")
public Department getDeptById(Integer id){
Department department=departmentMapper.getDeptById(id);
return department;
}
@Qualifier("deptCacheManager")
RedisCacheManager deptCacheManager;
//@Cacheable(cacheNames = "dept",cacheManager = "deptRedisCacheManager")
public Department getDeptById(Integer id){
Department department=departmentMapper.getDeptById(id);
//获取某个缓存
Cache dept = deptCacheManager.getCache("dept");
dept.put("dept",department);
return department;
}