spring boot2.3.2 redis缓存

spring boot2.3.2 redis缓存

在学习中,发现springboot2.x对缓存进行了优化,使复写率大大降低。但对应的,源码逻辑更加复杂,需要经过精心阅读才可以发现其中的奥妙。

一、实现代码

下面说一下springboot2.3.2版本使用redis进行缓存的代码:

实体类:
必须实现序列化,这是缓存存取数据的基础

public class Employee implements Serializable{
	
	private Integer id;
	private String lastName;
	private String email;
	private Integer gender; //性别 1男  0女
	private Integer dId;
	//此处省略getter,setter方法
}

持久层:
这里使用mybatis进行持久化操作

@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 Employee insertEmp(Employee employee);
}

业务逻辑层:
缓存操作做好是写在业务逻辑层,方便更好的管理对应操作。

@Service
public class EmployeeService {

	@Autowired
	EmployeeMapper employeeMapper;
	//此注解优先缓存中存取,如果缓存中有就不查询数据库再将数据存到redis做缓存,常用于查询操作
	//cacheNames时缓存的名字,key是缓存数据的键,通过这两个能确定缓存中的唯一数据
	@Cacheable(cacheNames={"emp"},key="#id"/*,condition = "#id>1"*/)//可以写spel表达式
	public Employee getEmp(Integer id){
		System.out.println("查询"+id+"号员工");
		Employee emp = employeeMapper.getEmpById(id);
		return emp;
	}
	//此注解先操作数据库中的数据(一定操作数据库),再将数据存到redis做缓存,常用于修改和新增操作
	@CachePut(cacheNames={"emp"},key="#result.id")
	public Employee updateEmp(Employee employee){
		System.out.println("update执行了"+employee);
		employeeMapper.updateEmp(employee);
		return employee;
	}
	//此注解先操作数据库,再清除缓存数据(注意指定cacheNames和key)
	@CacheEvict(cacheNames = {"emp"},key = "#id")
	public void deleteEmp(Integer id){
		System.out.println("删除了"+id+"号员工。");
	//	employeeMapper.deleteEmp(id);
	}
}

控制层:
这里使用restful风格,方便测试。

@RestController
public class EmployeeController {
	@Autowired
	EmployeeService employeeService;
	@GetMapping("/emp/{id}")
	public Employee getEmployee(@PathVariable("id") Integer id){
		Employee employee = employeeService.getEmp(id);
		return employee;
	}
	@GetMapping("/emp")
	public Employee updateEmpoyee(Employee employee){
		Employee employee1 = employeeService.updateEmp(employee);
		return employee1;
	}
	@GetMapping("/delemp/{id}")
	public String  deleteEmp(@PathVariable("id") Integer id){
		employeeService.deleteEmp(id);
		return "success";
	}
}

配置文件application.properties

#配置mybatis
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
mybatis.type-aliases-package=com.itjj.springboot.dao

#配置数据源
spring.datasource.url=jdbc:mysql://localhost:3306/spring_cache?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#开启驼峰命名规则:dId看成d_id
mybatis.configuration.map-underscore-to-camel-case=true

#开启测试报告
#debug=true

#打印某包下的日志
logging.level.com.itjj.springboot.mapper=debug

#配置redis
spring.redis.host=localhost

修改自定义序列化
序列化时spring默认使用jdk的序列化,我们难以阅读,所有使用json格式存储。
**注意:**此处操作再springboot2.x中进行了优化,下面配置只适用于springboot2.x

@Configuration
public class MyRedisConfiguration {

/*
	//如果直接使用redis模板进行操作,进行这段操作,
	//从默认的RedisConfiguration配置类中粘贴过来的,再进行自定义修改
	@Bean
	public RedisTemplate<Object, Employee> empRedisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		RedisTemplate<Object, Employee> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		//选择自己的序列化器,这选的时json
		RedisSerializer redisSerializer = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
		template.setDefaultSerializer(redisSerializer);
		return template;
	}
*/

	//修改默认的序列化
	//springboot1中,是每个实体类分别自定义配置CacheManager,配置方法是构造器传入上面自定义的RedisTemplate模板分别配置,且需要指定哪个为主配置
	//springboot2中直接使用RedisCacheConfiguration进行自定义配置,再使用RedisCacheManager的builder方法返回RedisCacheManagerBuilder对象,在调用该对象的cacheDefaults方法将自定义的RedisCacheConfiguration传入,再调用其build方法创建CacheManager方法,总结起来就是如下方法
	@Bean
	public CacheManager cacheManager(RedisConnectionFactory factory) {
		RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
				.entryTtl(Duration.ofDays(1))
				.disableCachingNullValues()
				.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
		return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();
	}

}

启动类:

@EnableCaching	//开启基于注解的缓存
@MapperScan("com.itjj.springboot.mapper")//指定扫描mapper的包
@SpringBootApplication
public class SpringbootCacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootCacheApplication.class, args);
    }

}

二、注意实现

在不使用缓存的时候, 用户实时查询的是数据库中的原生数据。不会出现查询结果与数据库数据不一致的问题。

而在使用redis缓存的时候,如果直接修改数据库中的数据(不经过程序),就会出现数据库中数据与缓存中数据不一致的问题,此时用户查询操作依然查的是缓存中的数据,解决此问题方法可以:修改数据库数据的同时,手动清除缓存中的对应数据。

此处依然有很多问题会发生,所以作为一个深入学习的启示,方便遇到问题时,了解问题产生的底层原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值