1 介绍
是阿里的双极缓存,jvm-->redis-->数据库
文档:jetcache/docs/CN at master · alibaba/jetcache · GitHub
2 注意事项
- 使用的实体类一定实现序列化接口
- 定时刷新注解,慎用 它会为每一个key创建一个定时器 :场景为:key少,访问量大
- 注解泛型一定和方法泛型保持一致,否则报错。
-
expire:过期时间设置为-1或者不设置 过期时间68年左右。
-
put入参key是null不会存数据,get入参为null,会报空指针。空字符串没有任务问题。使用缓存时我们要多封装一层,判断key为空时情况
- 版本
3 总结
缓存类型为BOTH时:
查询流程:
单机:本地缓存默认是100条数据(初始化数据时,留后查询的数据),redis留所有数据。本地缓存查询不到时,去redis找,保存到本地缓存,同时也去除一条本地缓存数据。
集群:第一次访问服务器A时,流程同上述一样,第二次访问服务器B时,直接去redis找,保存到本地缓存。
删除api:本地和redis都会删除数据
4 实战
4.1 pom
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.7.0</version>
</dependency>
<!-- jetcache2.7.x版本需要额外添加该依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
<!-- json数据工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
4.2 启动类:
@EnableMethodCache(basePackages="com.example.jetcache.mapper")
//如果不用@CreateCache注解可以删除 EnableCreateCacheAnnotation
@EnableCreateCacheAnnotation
4.3 配置文件
jetcache:
## 统计间隔,默认值0,0表示不统计,开启后定期在控制台输出缓存信息
statIntervalMinutes: 15
## 默认值false, 是否将 areaName 作为远程缓存key前缀
areaInCacheName: false
## 本地缓存配置
local:
default: ## default表示全部生效,也可以指定某个cacheName
## 本地缓存类型,其他可选:caffeine/linkedhashmap
type: caffeine
# 指定KEY的转换方式, 可选 fastjson2,fastjson,jackson
keyConvertor: fastjson
## 远程缓存配置
remote:
default: ## default表示全部生效,也可以指定某个cacheName
type: redis
## key转换器方式n
keyConvertor: fastjson
broadcastChannel: projectA
## redis序列化方式
valueEncoder: java
valueDecoder: java
## redis线程池
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
## redis地址与端口
host: 127.0.0.1
port: 6379
4.4 基础查询/删除/更新/定时刷新(慎用)
import com.alicp.jetcache.anno.*;
import com.example.jetcache.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Mapper
public interface UserMapper {
List<User> queryUserAll();
List<User> queryUser(User user);
/**
* BOTH类型查询
* expire 过期时间,redis和本地缓存一致
* 重启服务,本地jvm消失,会先查询redis,然后存入本地缓存
* 本地缓存存在,不会查询redis
*
*
* @param id
* @return
*/
@Cached(name="userCache:", key="#id", expire = 15 ,cacheType = CacheType.BOTH)
/**
* 只要是查询过的数据,就会定时刷新,从未查询过,则无定时刷新
* refresh: 定时器执行查询间隔时间-每过36秒就会执行一次定时器
* stopRefreshAfterLastAccess: 表示多久不使用对应的key缓存则会停止刷新。,如果不指定会一直刷新
refreshLockTimeout:类型为BOTH/REMOTE的缓存刷新时,同时只会有一台服务器在刷新,这台服务器会在远程缓存放置一个分布式锁,此配置指定该锁的超时时间
*/
@CacheRefresh(refresh = 36, stopRefreshAfterLastAccess = 3600, timeUnit = TimeUnit.SECONDS)
/**
* 注解作用——当缓存访问【未命中】的情况下,对并发进行的加载行为进行保护;当前版本实现的是单JVM内的保护,即同一个JVM中同一个key只有一个线程去加载,其它线程等待结果
*/
@CachePenetrationProtect
List<User> queryUserById(String id);
/**
* 删除
* @param id
* @return
*/
@CacheInvalidate(name="userCache.", key="#id")
int delById(int id);
@CacheUpdate(name="userCache.", key="#user.id", value="#user")
int save(User user);
}
4.5 CreateCache
//无则新增,有则覆盖
userCache.put(id,users);
//删除
userCache.remove(id);//删除所有数据暂无api
方式一:废弃了
@CreateCache(name= "userCache:", expire = 3600,cacheType = CacheType.BOTH)
private Cache<String, List<User>> userCache;
@PostMapping(value = "/queryUserById")
public List<User> queryUserById(@RequestParam String id) {
if(CollectionUtil.isNotEmpty(userCache.get(id) )){
return userCache.get(id);
}
List<User> users = userMapper.queryUserById(id);
//无则新增,有则覆盖
userCache.put(id,users);
return users;
}
方式二:spring注入直接使用,如上图使用API
@Autowired
private Cache<Long, Object> userCache;
@Configuration
public class JetCacheConfig {
@Autowired
private CacheManager cacheManager;
private Cache<String, List<User>> userCache;
@Resource(name = "userMapper")
private UserMapper userMapper;
@PostConstruct
public void init(){
QuickConfig qc = QuickConfig.newBuilder("userCache:")
.expire(Duration.ofSeconds(3600))
.cacheType(CacheType.BOTH)
//true 集群模式下,任何本地缓存都会强制删除缓存,fasle,则请求到哪个服务,哪个服务删除本地缓存,其他服务本地缓存保持不变
// 本地缓存更新后,将在所有的节点中删除缓存,以保持强一致性
// 两级缓存的情况下,缓存更新时发消息让其它JVM实例中的缓存失效,需要配置broadcastChannel才生效
.syncLocal(true)
// 默认100 后面数据会挤掉前面的数据 本地缓存元素个数限制,只对CacheType.LOCAL和CacheType.BOTH有效
.localLimit(100)
//不存在时则执行这个方法
.loader(this::loadOrderSumFromDatabase)
//newPolicy: 定时器执行查询间隔时间
// stopRefreshAfterLastAccess:表示多久不使用对应的key缓存则会停止刷新。
// .refreshPolicy(RefreshPolicy.newPolicy(6, TimeUnit.SECONDS).stopRefreshAfterLastAccess(10, TimeUnit.SECONDS))
//cache穿透保护注释表示缓存将在多线程环境中同步加载。
.penetrationProtect(true)
.build();
userCache = cacheManager.getOrCreateCache(qc);
//查询数据库,初始化全部数据
// userCache.putAll();
}
private List<User> loadOrderSumFromDatabase(String id) {
return userMapper.queryUserById(id);
}
@Bean
public Cache<String, List<User>> getUserCache(){
return userCache;
}
}