一、添加jetcache 依赖
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis-lettuce</artifactId>
<version>${jetcache.version}</version>
</dependency>
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>${jetcache.version}</version>
</dependency>
二、添加配置项
jetcache:
statIntervalMinutes: 15
areaInCacheName: false
local:
default:
type: linkedhashmap
keyConvertor: fastjson
remote:
default:
keyConvertor: fastjson
valueEncoder: kryo
valueDecoder: kryo
# redis
# type: redis
# host: 10.2.140.31
# port: 32263
# password: 123456
# database: 7
# lettuce
type: redis.lettuce
uri: redis://[email protected]:32263/7?timeout=5s
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
属性 | 默认值 | 说明 |
---|---|---|
jetcache.statIntervalMinutes | 0 | 统计间隔,0表示不统计 |
jetcache.areaInCacheName | true | jetcache-anno把cacheName作为远程缓存key前缀,2.4.3以前的版本总是把areaName加在cacheName中,因此areaName也出现在key前缀中。2.4.4以后可以配置,为了保持远程key兼容默认值为true,但是新项目的话false更合理些。 |
jetcache.hiddenPackages | 无 | @Cached和@CreateCache自动生成name的时候,为了不让name太长,hiddenPackages指定的包名前缀被截掉 |
jetcache.[local|remote].${area}.type | 无 | 缓存类型。tair、redis为当前支持的远程缓存;linkedhashmap、caffeine为当前支持的本地缓存类型 |
jetcache.[local|remote].${area}.keyConvertor | 无 | key转换器的全局配置,当前只有一个已经实现的keyConvertor:fastjson 。仅当使用@CreateCache且缓存类型为LOCAL时可以指定为none ,此时通过equals方法来识别key。方法缓存必须指定keyConvertor |
jetcache.[local|remote].${area}.valueEncoder | java | 序列化器的全局配置。仅remote类型的缓存需要指定,可选java和kryo |
jetcache.[local|remote].${area}.valueDecoder | java | 序列化器的全局配置。仅remote类型的缓存需要指定,可选java和kryo |
jetcache.[local|remote].${area}.limit | 100 | 每个缓存实例的最大元素的全局配置,仅local类型的缓存需要指定。注意是每个缓存实例的限制,而不是全部,比如这里指定100,然后用@CreateCache创建了两个缓存实例(并且注解上没有设置localLimit属性),那么每个缓存实例的限制都是100 |
jetcache.[local|remote].${area}.expireAfterWriteInMillis | 无穷大 | 以毫秒为单位指定超时时间的全局配置(以前为defaultExpireInMillis) |
jetcache.local.${area}.expireAfterAccessInMillis | 0 | 需要jetcache2.2以上,以毫秒为单位,指定多长时间没有访问,就让缓存失效,当前只有本地缓存支持。0表示不使用这个功能。 |
上表中${area}对应@Cached和@CreateCache的area属性。注意如果注解上没有指定area,默认值是"default"。
关于缓存的超时时间,有多个地方指定,澄清说明一下:
- put等方法上指定了超时时间,则以此时间为准
- put等方法上未指定超时时间,使用Cache实例的默认超时时间
- Cache实例的默认超时时间,通过在@CreateCache和@Cached上的expire属性指定,如果没有指定,使用yml中定义的全局配置,例如@Cached(cacheType=local)使用jetcache.local.default.expireAfterWriteInMillis,如果仍未指定则是无穷大
三、启用注解缓存
@EnableMethodCache(basePackages = "com.hikvision.smbg.content")
@EnableCreateCacheAnnotation
@Configuration
public class JetCacheConfig {
}
四、缓存常量类
public class CacheConst {
public static class ContentDetail {
public static final String redisKeyPrefix = "content:detail:";
public static final int expire = 60 * 60 * 24;
}
public static class Content {
public static final int sign = 0;
public static final String redisKeyPrefix = "content:user:like:";
}
public static class Comment {
public static final int sign = 1;
public static final String redisKeyPrefix = "comment:user:like:";
}
public static class CommentReply {
public static final int sign = 2;
public static final String redisKeyPrefix = "commentReply:user:like:";
}
public static class CommentLike {
public static final String redisKeyPrefix = "comment:like:";
public static final int expire = 60;
}
public static class ContentView {
public static final String redisKeyPrefix = "content:view:";
public static final int expire = 60;
}
public static class ContentLike {
public static final String redisKeyPrefix = "content:like:";
public static final int expire = 60;
}
public static class ContentFavourite {
public static final String redisKeyPrefix = "content:favourite:";
public static final int expire = 60;
}
}
五、注解缓存使用
(1)一般在获取详情列表等大的不经常变动的数据接口上面 使用 @Cached 注解进行缓存的创建,把数据缓存到redis中,指定key,过期时间等。
@Cached(name = CacheConst.ContentDetail.redisKeyPrefix, key = "#response.contentId",
expire = CacheConst.ContentDetail.expire, timeUnit = TimeUnit.DAYS)
@Override
public ContentBaseResponse assembleDetail(ContentBaseResponse response) {
// 获取兴趣标签
List<Long> labelIds = this.listLabelIdsByContentId(response.getContentId());
response.setLabelIds(labelIds);
// 获取案例轮播图
List<String> picUrls = this.listPicUrlsByContentIdAndPicType(response.getContentId(), PicTypeEnum.MAIN.getCode());
response.setPicUrls(picUrls);
// 获取产品清单
List<GoodsResponse> goods = this.listGoodsByContentId(response.getContentId());
response.setGoods(goods);
// 获取附件列表
List<AttachResponse> attachs = this.listAttachByContentId(response.getContentId());
response.setAttachs(attachs);
// 获取评论
// List<CommentResponse> comments = this.listCommentByContentId(response.getContentId());
// response.setComments(comments);
return response;
}
四、当对要查询的大数据详情,列表进行的更新操作的时候,添加@CacheInvalidate 注解,使其 删除(销毁),这样在查询的时候就会重新把最新的数据缓存到redis中,
这样就保证的数据库的最终一致性
@CacheInvalidate(name = CacheConst.ContentDetail.redisKeyPrefix, key = "#contentId")
@Transactional(rollbackFor = Exception.class)
@Override
public void update(CaseUpdateRequest request, Long contentId) {
// 获取客户案例
CaseDO dataobject = getDataobjectByContentId(contentId);
// 客户案例权限校验
if (ContentFromEnum.MERCHANT.getCode().equals(dataobject.getCaseFrom())) {
String creator = dataobject.getCreator();
String modifier = request.getModifier();
if (!StringUtils.equals(creator, modifier)) {
throw new ContentCenterException(100002, "平台或商家【" + modifier + "】没有权限编辑客户案例【" + contentId + "】");
}
}
....
....
}