我们使用java的spring-boot进行redis开发。
Redis开发分为两种:
(一)编程式缓存
(1)导入Rdis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
(2)在application.properties中进行文件配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-wait=100ms
spring.redis.jedis.pool.max-idle=100
spring.redis.jedis.pool.min-idle=10
(3)编写一个配置类
配置RedisTemplate
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// 配置序列化器
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化器
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
(4)使用缓存的步骤
-
先查询缓存
-
如果查到直接返回
-
如果查不到,查询数据库
-
数据库查到,保存缓存中
-
数据库查不到返回null
@Service
public class CarServiceImpl extends ServiceImpl<CarMapper, Car> implements CarService {
@Autowired
private CarMapper carMapper;
public static final String PREFIX="Car-";
@Autowired
private RedisTemplate<String,Object> redisTemplate;
//设置同步锁验证
@Override
public Car getCarById(Long id) {
//获取字符串操作对象
ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//先查询Redis
Car car = (Car)ops.get(PREFIX + id);
if (car == null){
synchronized (this){
System.out.println("进入同步锁");
//先查询Redis
car = (Car)ops.get(PREFIX + id);
//如果redis是存在的,就会直接返回
if (car!=null){
System.out.println("redis查到了,返回"+car);
return car;
}
//如果redis没有查到数据,就查mysql
car = carMapper.selectById(id);
//mysql查到数据,保存到redis
if (car!=null){
System.out.println("mysql查到,返"+car);
ops.set(PREFIX+id,car);
return car;
}else {
//mysql没有数据
System.out.println("mysql没数据");
Car car1 = new Car();
//设置存在的期限
ops.set(PREFIX+id,car1,50, TimeUnit.SECONDS);
}
// mysql没有数据,返回null
System.out.println("mysql没数据,返回null");
}
}else {
System.out.println("没有执行同步锁");
}
return car;
}
}
(5)最后在control层编写接口
@GetMapping("/car/{id}")
public ResponseResult<Car> getStudentById(@PathVariable Long id){
return ResponseResult.ok(carService.getCarById(id));
}
(二)声明式缓存
编程式缓存使用复杂,代码侵入性高,推荐使用声明式缓存,通过注解来实现热点数据缓存。
(1)在启动类上添加注解
//启动缓存
@EnableCaching
(2)redis配置类
@Bean
public RedisCacheConfiguration provideRedisCacheConfiguration(){
//加载默认配置
RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig();
//返回Jackson序列化器
return conf.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
(3)缓存相关的注解
缓存相关注解
@CacheConfig 使用在Service类上,可以配置缓存名称,如: @CacheConfig(cacheNames = "car")
@Cacheable 使用在查询方法上,让方法优先查询缓存
@CachePut 使用在更新和添加方法上,数据库更新和插入数据后同时保存到缓存里
@CacheEvict 使用在删除方法上,数据库删除后同时删除缓存
Redis缓存汽车案例
//查看分页
@Cacheable(cacheNames = "Car-Page",key = "T(String).valueOf(#current)")
@Override
public Page<Car> getCarPage(Long current, Long size) {
return carMapper.selectCar(new Page<>(current,size));
}
组合注解@Cacing
//移除
@Caching(
evict = {
@CacheEvict(cacheNames = "Car",key = "T(String).valueOf(#id)"),
@CacheEvict(cacheNames = "Car-Page",allEntries = true)
}
)
@Override
public void removeCarById(Long id) {
carMapper.deleteById(id);
}
//修改
@Caching(
put = @CachePut(cacheNames = "Car",key = "T(String).valueOf(#car.id)"),
evict = @CacheEvict(cacheNames = "Car-Page",allEntries = true)
)
@Override
public Car updateCarById(Car car) {
carMapper.updateById(car);
return car;
}
//添加
@Caching(
put = @CachePut(cacheNames = "Car",key = "T(String).valueOf(#car.id)"),
evict = @CacheEvict(cacheNames = "Car-Page",allEntries = true)
)
@Override
public Car addCarById(Car car) {
carMapper.insert(car);
return car;
}
总结:
编程式缓存适用于复杂的缓存场景,需要更多的灵活性和控制;而声明式缓存适用于简单的缓存需求,可以更快速地实现缓存功能并减少开发工作量。在具体项目中选择缓存方式时,需要根据实际情况综合考虑缓存策略的复杂度、开发效率和维护成本等因素。