springboot caffeine+redis实现二级缓存笔记
一、前言最近在项目中发现了用到caffeine+redis的地方,感觉写的很好,因此记一波笔记。caffeine是spring的cache,保存在项目本地。redis是分布式缓存,保存在redis服务器。查询数据时,先到caffeine中查,如果没有则查redis,如果还没有再查数据库。二、主要流程代码样例1.查询数据库的Java类ExamServiceImpl.java@Servicepubli
一、前言
最近在项目中发现了用到caffeine+redis的地方,感觉写的很好,因此记一波笔记。
caffeine是spring的cache,保存在项目本地。
redis是分布式缓存,保存在redis服务器。
查询数据时,先到caffeine中查,如果没有则查redis,如果还没有再查数据库。
二、主要流程代码样例
1.查询数据库的Java类ExamServiceImpl.java
@Service
public class ExamServiceImpl implements ExamService {
@Autowired
private ExamRepository examRepository;
@Override
public Exam get(Long id) {
com.google.common.base.Preconditions.checkNotNull(id);
return examRepository.selectById(id);
}
}
2.查询Redis的Java类ExamServiceProxy.java(继承ExamServiceImpl)
@Service
@Primary
public class ExamServiceProxy extends ExamServiceImpl {
@Autowired
private StringRedisTemplate redis;
@Autowired
ObjectMapper objectMapper;
@Override
public Exam get(Long id){
com.google.common.base.Preconditions.checkNotNull(id);
//从缓存中取value
String value = redis.opsForValue().get(String.format("exam:%s",id));
Exam exam = null;
if(!StringUtils.isBlank(value)){
try{
//把value转换成对象
exam = obejctMapper.readValue(value, Exam.class);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
//如果缓存里没有或value错误
if(exam == null){
//查数据库
exam = super.get(id);
if(exam != null) {
//如果查数据库有(此时redis为空或value错误),则存入redis
String key = String.format("exam:%s",id);
//把对象转换成value字符串
try{
String objToStr = objectMapper.writeValueAsString(exam);
//存入redis,过期时间7天
redis.opsForValue().set(key,objToStr,7,TimeUnit.DAYS);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
//返回结果
return exam;
}
}
3.查询caffeine的Java类ExamServiceProxy2(继承ExamServiceProxy)
@Service
public class ExamServiceProxy2 extends ExamServiceProxy {
@Autowired
private Cache cache;
@Override
public Exam get(Long id){
Preconditions.checkNotNull(id);
String key = String.format("exam:%s",id);
//查询caffeine,没有则使用super从redis查
return cache.get(key, ()-> super.get(id));
}
//存caffeine的逻辑是单独写的(应该也能写到get逻辑里,不过没有写)
@Override
public List<Exam> listByIds(Collection<Long> ids){
.....
cache.put(String.format("exam:%s",exam.getId()),exam);
.....
}
}
4.使用样例(使用Qualifier指定即可)
@Autowired
@Qualifier("examServiceProxy2")
private ExamService examService;
三、总结
1.通过继承,实现了先查caffeine缓存、再查redis缓存、最后查数据库的逻辑结构。
2.注意Exam类需要implements Serializable
;存入caffeine时,直接存入Exam对象即可;存入redis时,使用了ObjectMapper
把Exam对象转换为字符串,然后再存入的。
3.要使用caffeine缓存,可以写一个配置类,然后使用@Autowired注入Cache对象;要使用redis,可以在yml中配置redis的url、账号密码等,然后使用@Autowired注入StringRedisTemplate对象。(当然还有相关jar包等)
4.caffeine配置类样例CacheConfig.java
@Configuration
public class CacheConfig {
public static final String CACHE_NAME="caffeine";
//参数从properties/yml中读取;冒号后是默认值,没有读取到值,就用冒号后的参数
@Value("${spring.cache.caffeine.spec:recordStats,maximunSize=300000,expireAfterWrite=10s}")
private String caffeineSpec;
@Bean("caffeineCacheManager")
public CaffeineCacheManager getCaffeineCacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCacheNames(Collections.singleton(CACHE_NAME));
cacheManager.setCacheSpecification(caffeineSpec);
cacheManager.setAllowNullValues(true);
return cacheManager;
}
@Bean
public Cache getCaffeineCache(@Qualifier("caffeineCacheManager") CacheManager cacheManager){
return cacheManager.getCache(CACHE_NAME);
}
}
相关maven:
<properties>
<spring.version>5.0.10.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
注入使用方式:
@Autowired
private Cache cache;
5.redis配置样例application.properties
spring.redis.database=1
spring.redis.host=10.123.123.123
spring.redis.port=37652
spring.redis.password=abcdef123456
相关maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
启动类Application.java注解:
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 2 * 3600)
注入使用:
@Autowired
private StringRedisTemplate redis;
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)