JetCache 是阿里出品的一款缓存框架,其提供了基于接口的缓存以及能够实现本地和远程二级缓存(本地缓存是当前 JVM 中的LinkedHashMap,远程缓存为Redis),在提高系统吞吐量的同时,也极大地方便了代码编写。本文将介绍基于 Spring Boot 2.5 简易集成缓存框架 JetCAche 2.7。
JetCache Github: https://github.com/alibaba/jetcache
./demo-mybatis-plus/pom.xml
<dependency>
<groupId>com.alicp.jetcachegroupId>
<artifactId>jetcache-starter-redis-lettuceartifactId>
<version>${jetcache.version}version>
dependency>
其中版本信息为:
<jetcache.version>2.7.3jetcache.version>
本示例中使用的是 lettuce 作为 Redis 连接工具
./demo-mybatis-plus/src/main/resources/application.yml
# jetCache
jetcache:
statIntervalMinutes: 1
areaInCacheName: false
local:
jetcache-demo:
type: linkedhashmap
keyConvertor: jackson
remote:
jetcache-demo:
type: redis.lettuce
keyConvertor: jackson
broadcastChannel: jetcache-demo
keyPrefix: jetcache-demo
valueEncoder: java
valueDecoder: java
uri: redis://[email protected]:6379
defaultExpireInMillis: 5000
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
注意:
jetcache.local.jetcache-demo
: 这里的 jetcache-demo
是作为缓存区域(area
)命名的,必须与代码中的 area
定义保持一致,否则就会启动失败,抛出com.alicp.jetcache.CacheConfigException: no local cache builder
异常。
同理 jetcache.remote.jetcache-demo
中jetcache-demo
也是一样的。一般同一个项目(业务模块)使用同样的 area
命名。
官方配置信息说明:
https://github.com/alibaba/jetcache/blob/master/docs/CN/Config.md
官方文档注解说明:
https://github.com/alibaba/jetcache/blob/master/docs/CN/MethodCache.md
一些常用注解的补充说明:
@Cached
:标记缓存注解,用于方法上,一般用于查询方法上常用参数包括:
注解参数 | 说明 |
---|---|
area | 区域,必须定义的与 application 里边的保持一致(local/remote 后一级的参数名),否则运行报错 |
name | 缓存的 key(前缀) |
key | 缓存的key后边部分,拼在name后边,可缺省,定义的key必须在请求参数中包括,否则报错,无法缓存 |
expire | 缓存失效时间,默认单位:秒 |
localExpire | 本地缓存失效时间,默认单位:秒 |
cacheType | 缓存类型,有本地,远程和两者都包含可选,简易使用CacheType.BOTH |
localLimit | 本地缓存数量限制 |
@CacheInvalidate
:缓存失效注解,用于方法上,一般用于更新或者删除方法上。
@CachePenetrationProtect
: 指定未命中缓存的情况下,同一个 JVM 同一个 key 只有一个线程去操作,用于防止并发请求。
./demo-mybatis-plus/src/main/java/com/ljq/demo/springboot/mybatisplus/service/impl/JetCacheUserServiceImpl.java
package com.ljq.demo.springboot.mybatisplus.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.anno.CacheInvalidate;
import com.alicp.jetcache.anno.CachePenetrationProtect;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljq.demo.springboot.mybatisplus.common.constant.JetCacheConst;
import com.ljq.demo.springboot.mybatisplus.dao.UserDao;
import com.ljq.demo.springboot.mybatisplus.model.entity.UserEntity;
import com.ljq.demo.springboot.mybatisplus.model.param.user.*;
import com.ljq.demo.springboot.mybatisplus.service.IJetCacheUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Objects;
/**
* @Description: JetCache 缓存示例用户业务实现类
* @Author: junqiang.lu
* @Date: 2023/3/25
*/
@Service
public class JetCacheUserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements IJetCacheUserService {
/**
* 保存(单条)
*
* @param userSaveParam
* @return
*/
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
@Override
public UserEntity save(UserSaveParam userSaveParam) {
// 请求参数获取
UserEntity userParam = new UserEntity();
BeanUtil.copyProperties(userSaveParam,userParam,CopyOptions.create().ignoreNullValue().ignoreError());
// 保存
String nowTime = String.valueOf(System.currentTimeMillis());
userParam.setUserInsertTime(nowTime);
userParam.setUserUpdateTime(nowTime);
super.save(userParam);
return userParam;
}
/**
* 查询详情(单条)
*
* @param userInfoParam
* @return
*/
@CachePenetrationProtect
@Cached(area = JetCacheConst.CACHE_AREA, name = ":getUserById", key = "#userInfoParam.id",
cacheType = CacheType.BOTH, expire = 300, localExpire = 180)
@Override
public UserEntity info(UserInfoParam userInfoParam) {
return super.getById(userInfoParam.getId());
}
/**
* 查询列表
*
* @param userListParam
* @return
*/
@Override
public IPage<UserEntity> list(UserListParam userListParam) {
LambdaQueryWrapper<UserEntity> userWrapper = Wrappers.lambdaQuery();
userWrapper.likeRight(StrUtil.isNotBlank(userListParam.getUserName()), UserEntity::getUserName,
userListParam.getUserName());
IPage<UserEntity> page = new Page<>(userListParam.getCurrentPage(),userListParam.getPageSize());
userWrapper.orderBy(true, Objects.isNull(userListParam.getAscFlag()) ?
false : userListParam.getAscFlag(), UserEntity::getId);
return super.page(page,userWrapper);
}
/**
* 更新(单条)
*
* @param userUpdateParam
* @return
*/
@CacheInvalidate(area = JetCacheConst.CACHE_AREA, name = ":getUserById", key = "#userUpdateParam.id")
@Override
public UserEntity update(UserUpdateParam userUpdateParam) {
LambdaQueryWrapper<UserEntity> userWrapper = new LambdaQueryWrapper<>();
userWrapper.eq(true, UserEntity::getId, userUpdateParam.getId());
int countUser = super.count(userWrapper);
if (countUser < 1) {
return null;
}
// 请求参数获取
UserEntity userParam = new UserEntity();
BeanUtil.copyProperties(userUpdateParam, userParam, CopyOptions.create().ignoreNullValue().ignoreError());
userParam.setUserUpdateTime(String.valueOf(System.currentTimeMillis()));
super.updateById(userParam);
return userParam;
}
/**
* 删除(单条)
*
* @param userDeleteParam
* @return
*/
@CacheInvalidate(area = JetCacheConst.CACHE_AREA, name = ":getUserById", key = "#userDeleteParam.id")
@Override
public boolean delete(UserDeleteParam userDeleteParam) {
boolean deleteFlag = super.removeById(userDeleteParam.getId());
if (!deleteFlag) {
return false;
}
return true;
}
}
注意事项:
这里对于同一业务模块的area
和 name
要保持一致。area
可以用一个常量类来保存,name
可以在前边添加:
这样在Redis数据库中可以分级显示。
说明:
由于 JetCache 默认使用的是 Java提供的序列化,所以在 Redis 中看到的效果就是这样的,JetCache 2.7 版本官方不提供 Json 序列化方式,需要自行实现(后期再来更新)。
JetCache官方文档
记录使用JetCache遇到的问题
Gtihub 源码地址 : https://github.com/Flying9001/springBootDemo
个人公众号:404Code,分享半个互联网人的技术与思考,感兴趣的可以关注.