前言
掌握了Redis的几大数据类型后,本章我们将学习在Java项目中如何使用Redis实现缓存。
编程式缓存
通过SpringBoot整合Redis的方式来实现缓存商品。
1)导入Redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2)添加配置文件
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)使用RestTemplate
常用方法:
- ValueOperations opsForValue() 获得string类型的操作对象
- HashOperations opsForHash 获得hash类型的操作对象
- …
ValueOperations操作对象
- set(key,value) 保存key-value
- Object get(key) 读取value
使用缓存的步骤:
- 先查询缓存
- 如果查到直接返回
- 如果查不到,查询数据库
- 数据库查到,保存缓存中
- 数据库查不到返回null
@Override
public Goods findById(Long id) {
ValueOperations<String, Object> ops = template.opsForValue();
//先查缓存,缓存有,直接返回不执行同步块,提高效率
Goods goods = (Goods ) ops.get("goods-"+id);
if(goods == null) {
//上锁,保证查询缓存,查询数据库,保存缓存同步执行
synchronized (this) {
//先查询缓存
goods = (Goods ) ops.get("goods-" + id);
//如果查到直接返回
if (goods!= null) {
System.out.println("从缓存查到" + goods);
return goods;
} else {
//如果查不到,查询数据库
System.out.println("缓存没有,查询数据库");
goods = goodsMapper.selectById(id);
if (goods!= null) {
//数据库查到,保存缓存中
System.out.println("数据库查到" + goods);
ops.set("goods-" + id, goods);
return goods;
}
}
System.out.println("数据库没有查到");
return null;
}
}
return goods;
}
声明式缓存
编程式缓存使用复杂,代码侵入性高,推荐使用声明式缓存,通过注解来实现热点数据缓存。
1)在启动类上添加注解
//启动缓存
@EnableCaching
2)Redis的配置类
@Configuration
public class RedisConfig {
@Bean
public RedisCacheConfiguration provideRedisCacheConfiguration(){
//加载默认配置
RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig();
//返回Jackson序列化器
return conf.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
3)缓存相关注解
- @CacheConfig 使用在Service类上,可以配置缓存名称,如:
@CacheConfig(cacheNames = “books”) - @Cacheable 使用在查询方法上,让方法优先查询缓存
- @CachePut 使用在更新和添加方法上,数据库更新和插入数据后同时保存到缓存里
- @CacheEvict 使用在删除方法上,数据库删除后同时删除缓存
注意:缓存的实体类必须实现序列化接口
案例:Reids缓存品牌
//配置缓存名称为brand
@CacheConfig(cacheNames = "brand")
@Service
public class BrandServiceImpl extends ServiceImpl<BrandMapper, Brand> implements IBrandService {
@Autowired
private BrandMapper brandMapper;
//按分类查询品牌时进行缓存,缓存名称是brand-category,键是分类id
@Cacheable(cacheNames = "brand-category",key = "T(String).valueOf(#cid)")
@Override
public List<Brand> findBrandsByCategory(Integer cid) {
return brandMapper.selectBrandsByCategory(cid);
}
//缓存单个品牌
@Cacheable(key = "T(String).valueOf(#id)")
@Override
public Brand findBrandById(Long id) {
return this.getById(id);
}
//修改品牌时更新缓存
@CachePut(key = "T(String).valueOf(#brand.id)")
@Override
public Brand saveBrand(Brand brand) {
this.saveOrUpdate(brand);
return brand;
}
//删除品牌时删除缓存
@CacheEvict(key = "T(String).valueOf(#id)")
@Override
public void deleteBrand(Long id) {
this.removeById(id);
}
//缓存分页
@Cacheable(cacheNames = "brand-page",key = "T(String).valueOf(#page)")
@Override
public IPage<Brand> pageBrands(Long page) {
return this.page(new Page<>(page,10));
}
}
结束
大家如果需要学习其他Java知识点,戳这里 超详细的Java知识点汇总