SpringBoot2 & RedisCacheManager
1.mysql准备
在 mysql 数据库中建立 database 以及建表 department & employee
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;
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;
然后在application.properties中建立连接
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#时区错误 加?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8为后缀
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring_cache?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=xxxxxxx----yourpassword
#开启驼峰命名匹配规则
mybatis.configuration.map-underscore-to-camel-case=true</pre>
2.建立实体类
目录结构
public class Department implements Serializable { //在这里序列化需要后期的redis缓存时需要
private Integer id;
private String departmentName;
@Override
public String toString() {
return "Department{" +
"id=" + id +
", departmentName='" + departmentName + '\'' +
'}';
}
public Department() {
super();
}
public Department(Integer id, String departmentName) {
this.id = id;
this.departmentName = departmentName;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
}
public class Employee implements Serializable {
private Integer id;
private String lastName;
private String email;
private Integer gender;
private Integer dId;
public Employee() {
super();
}
public Employee(Integer id, String lastName, String email, Integer gender, Integer dId) {
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
this.dId = dId;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", gender=" + gender +
", dId=" + dId +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Integer getdId() {
return dId;
}
public void setdId(Integer dId) {
this.dId = dId;
}
}
3.mapper & service & controller
1.mapper
@Mapper
public interface DepartmentMapper {
@Select("select * from department where id = #{id}")
public Department getDeptById(Integer id);
}
@Mapper
public interface EmployeeMapper {
@Select("select * from employee where id = #{id}")
public Employee getEmpById(Integer id);
@Update("update employee set lastName=#{lastName}, email=#{email}, gender=#{gender}, d_id=#{dId} where id=#{id} ")
public void updateEmp(Employee employee);
@Delete("delete from employee where id=#{id}")
public void deleteEmp(Integer id);
@Insert("insert into employee(lastName,email,gender,d_id}values (#{lastName},#{email},#{gender},#{dId} ))")
public void insertEmploree(Employee employee);
@Select("select * from emplyee where lastName = #{lastName}")
public Employee getEmpByLastName(String lastName);
}
2service
@Service
public class DepartmentService {
@Autowired
DepartmentMapper departmentMapper;
@Cacheable(cacheNames = { "dept" }/*, condition = "#a0>1", unless = "#a0==2"*/)
public Department getDept(Integer id) {
System.out.println("查询"+ id +"号部门。" );
Department dept = departmentMapper.getDeptById(id);
return dept;
}
}
@CacheConfig(cacheNames = "emps") //抽取缓存的公共配置 虽然没用到哈哈
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中取,不用调用方法
*
* CacheManager管理多个Cache组件的,对缓存的真正CRUD操作再Cache组件中,每一个缓存组件有自己唯一一个名字
* 几个属性:
* cacheNames/value:指定缓存组件的名字;
* key:缓存数据使用的key,可以用它来指定。默认是使用方法的参数的值 1-方法的返回值
* 编写SpEL; #id;参数id的值 #a0 #p0 #root.args[0]
* keyGenerator:key的生成器;可以自己指定key的生成器的组件id
* key/keyGenerator:二选一使用
* cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器 它俩也是二选一使用
* condition:指定符合条件的情况下才缓存
* ,condition = "#id>0"
* unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
* unless = "#result == null"
* sync:是否使用异步模式
*
*
* 原理:
* 1、自动配置类 CacheAutoConfiguration
* 2、缓存的配置
*
*
* @param id
* @return
*/
@Cacheable(cacheNames = { "emp" }/*, 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、将目标方法的结果缓存起来
* @param employee
* @return
*
*
* 测试步骤:
* 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 : 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
*
* @param id
*/
@CacheEvict(value = "emp", key = "#id")
public void deleteEmp(Integer id) {
System.out.println("deleteEmp : "+id);
// employeeMapper.deleteEmp(id);
}
/**
* @Cacheing : 定义复杂的缓存规则
* @param lastName
* @return
*/
@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);
}
}
3.controller
@RestController
public class DepartmentController {
@Autowired
DepartmentService departmentService;
@GetMapping("/dept/{id}")
public Department getDepartment(@PathVariable("id") Integer id) {
return departmentService.getDept(id);
}
}
@RestController
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping("/emp/{id}")
public Employee getEmployee(@PathVariable("id") Integer id) {
Employee emp = employeeService.getEmp(id);
return emp;
}
@GetMapping("/emp")
public Employee update(Employee employee) {
Employee emp = employeeService.updateEmp(employee);
return emp;
}
@GetMapping("deleteemp")
public String deleteEmp(Integer id) {
employeeService.deleteEmp(id);
return "success";
}
@GetMapping("/emp/lastname/{lastName}")
public Employee getEmpByLastName(@PathVariable(value = "lastName") String lastName) {
return employeeService.getEmpByLastName(lastName);
}
}
4.自定义配置类 MyRedisConfig
第三步完了后就可以自己测一测了。
注意的是既然连接redis , 当然就需要你启动你的redis服务,然后在启动类上加上注解@MapperScan(basePackage = {"你的mapper包比如<com.as.cache.mapper>"})
@EnableCaching
开启缓存注解
接下来你就可以自己测一测 ,是不是在走的是redis缓存了。
只是这个时候走的缓存是RedisCacheConfiguration类下RedisCacheManager。
而且redis缓存的是默认的 jdk 序列化的,如果想要自定义序列化为 json 需要重写RedisCacheManager
@Configuration
public class MyRedisConfig {
//这个是自定义的一个用来测试时的 redisTemplate
@Bean
public RedisTemplate<Object, Employee> empRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Employee> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 转换 格式
Jackson2JsonRedisSerializer<Employee> employeeJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
template.setDefaultSerializer(employeeJackson2JsonRedisSerializer);
return template;
}
/**
* 基于SpringBoot2 对 RedisCacheManager 的自定义配置
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
//设置CacheManager的值序列化方式为json序列化
RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();
RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
//设置默认超过时期是1天
defaultCacheConfig.entryTtl(Duration.ofDays(1));
//初始化RedisCacheManager
return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
}
}
5.测试类 & 启动类
1.测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class CacheApplicationTests {
@Autowired
EmployeeMapper employeeMapper;
@Autowired
StringRedisTemplate stringRedisTemplate; //操作k-v都是字符串的
@Autowired
RedisTemplate redisTemplate; //k-v都是对象
@Autowired
RedisTemplate<Object, Employee> empRedisTemplate;
/**
* Redis常见五大类型:
* String(字符串)、list(列表)、Set(集合)、Hash(散列)、ZSet(有序集合)
* stringRedisTemplate.opsForValue() [String(字符串)]
* stringRedisTemplate.opsForList() [list(列表)]
* stringRedisTemplate.opsForSet() [Set(集合)]
* stringRedisTemplate.opsForHash() [SHash(散列)]
* stringRedisTemplate.opsForZSet() [ZSet(有序集合)]
*/
@Test
public void test01() {
//给redis中保存数据
// stringRedisTemplate.opsForValue().append("msg", "hello");
// String msg = stringRedisTemplate.opsForValue().get("msg");
// System.out.println(msg);
stringRedisTemplate.opsForList().leftPush("mylist", "1");
stringRedisTemplate.opsForList().leftPush("mylist", "2");
}
@Test
public void test02() {
Employee empById = employeeMapper.getEmpById(1);
//默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
// redisTemplate.opsForValue().set("emp-01", empById);
//1、将数据以json的方式保存
//(1)自己将对象转为json
//(2)redisTemplate默认的序列化规则;改变默认的序列化规则;
empRedisTemplate.opsForValue().set("emp-01", empById);
System.out.println(empById);
}
}
2.启动类
/**
* 4、测试缓存
* 原理:CacheManager===Cache 缓存组件来实际给缓存中存取数据
* 1)、引入redis的starter,容器中保存的是 RedisCacheManager;
* 2)、RedisCacheManager 帮我们创建 RedisCache 来作为缓存组件; RedisCache通过操作redis缓存数据的
* 3)、默认保存数据 k-v 都是Object;利用序列化保存;如何保存为json
* 1、引入了redis的starter,cacheManager变为 RedisCacheManager;
* 2、默认创建的 RedisCacheManager 操作redis的时候使用的是 RedisTemplate<Object, Object>
* 3\RedsiTemplate<Object, Object> 是 默认使用 jdk 的序列化机制
* 4)、自定义 CacheManager ;
*/
@SpringBootApplication
@MapperScan(basePackages = {"com.liyanyan.cache.mapper"})
@EnableCaching
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
主要解释都在 代码的注释里 学的时候直接敲进去的,嫌麻烦就没有整理出来,以后有时间再抽离整理吧
学习 尚硅谷的springboot高级视频时 的学习笔记