直接入主题,先说引用和使用方法
引用root pom
<parent> <groupId>com.weishi</groupId> <artifactId>weishi-root-pom</artifactId> <version>experiment-1.0.9-RELEASE</version> </parent> |
底层依赖实际:
<weishi-toolkit-common-version>experiment-1.0.8-RELEASE</weishi-toolkit-common-version> <weishi-toolkit-starter-version>experiment-1.0.1-RELEASE</weishi-toolkit-starter-version> <weishi-jetcache-version>2.7.21-RELEASE</weishi-jetcache-version> |
Service 配置
在你的Service 上面继承 ICacheQueryService
比如你的 Service 是 AssignmentService, 那么抽象类和实现类如下
public interface AssignmentService extends ICacheQueryService<AssignmentEntity> { } public class AssignmentServiceImpl extends AbstractCacheQueryServiceImpl<AssignmentMapper, AssignmentEntity> implements AssignmentService { @CreateCache(name = "zy_assignment", localLimit = 5000, expire = 30, localExpire = 15) private Cache<Serializable, AssignmentEntity> assignmentEntityCache; @Override public SFunction<AssignmentEntity, ?> getIdSFun() { return AssignmentEntity::getId; } @Override public Cache<Serializable, AssignmentEntity> getCache() { return assignmentEntityCache; } @Override protected QueryCacheConfig queryCacheConfig() { return new QueryCacheConfig().setLimit(CacheConsts.DEFAULT_LOCAL_LIMIT * 30).setExpireAfterWriteInMillis( 3 * 60 * 1000L ); } } |
实现几个默认 需 实现类, 加入必须的Cache, 这里可以调节 query cache 的一些参数 默认 为
@Accessors(chain = true) @Data public class QueryCacheConfig { private long expireAfterWriteInMillis = 10 * 1000L; private int limit = CacheConsts.DEFAULT_LOCAL_LIMIT * 10; } |
expireAfterWriteInMillis: 过期时间
limit: 本地缓存容量
进程级别缓存 query cache
怎么使用查询增强
example: AssignmentEntity assignmentEntity = lambdaQueryPlus().eq(AssignmentEntity::getClassroomId, classId). eq(AssignmentEntity::getHomeworkId, homeworkId).oneWithQueryCache(); ClassroomEntity entity = classroomService.lambdaQueryPlus().eq(ClassroomEntity::getUserId, userId) .eq(ClassroomEntity::getName, dto.getName()).eq(ClassroomEntity::getIsDeleted, false).oneWithQueryCache(); |
基于原有的 mybatis plus 的链式查询功能, 把内嵌的缓存查询,无感知引入。 当一次查询进入DB,第二次相同的查询进行,当查询缓存没有过期的情况下,可以直接从缓存中取值。
当需要删除特定的Entity的时候, 使用 lambdaUpdatePlus 同步删除管理已缓存的查询, 查询缓存的管理无需我们操心,直接删除你想要的数据即可。
例子
example: homeworkResourceService.lambdaUpdatePlus().eq(HomeworkResourceEntity::getHomeworkId, homeworkId).remove(); 或者直接使用 homeworkResourceService.removeById(123L) 这样也能删除对应 id 关联的 条件查询缓存 |
上述使用都是基于分布式缓存通知,无需担心,多台机器造成缓存不一致问题
基本使用已经说完, 使用基本是黑盒无感知的。
使用场景
- 在条件查询比较多需要查询单体Entity(单张表特定数据) 会比较有效
- 读多写少的场景,一般来说 读写比例在 或超过八比一 都可以认为是读多写少,一般互联网创作者创造资源,用户读取资源, 都是读多写少场景,操纵资源的次数较少
优缺点
- 优点
能带来显著的查询缓存能力增强, 对于热点数据的条件查询,性能提升巨大
无需手动管理 查询缓存和 id的关联关系,无需关注缓存和db数据不一致问题
2. 缺点
使用queryCache 的Service, 删除更新数据时候,会带来多台机器的订阅通知,带来一些性能损耗
Q&A 环节
Q1: 这个和 DB层面的缓存有点类型,它们一样吗
不一样, DB层面的缓存最大的问题,它是基于单张表的, 就是说单张表如果有插入删除行为,那么关联到此张表的所有查询缓存都会实现,这样来看这种缓存就是鸡肋, 因为 更新删除某种表的数据,对于表层面是 很容易发生的,这样的话查询缓存极为容易过期,使得缓存没有太大意义。
而我找个单entity 条件查询缓存优化 是基于表中的某行数据的, 也就是用户不同行的查询,是互不影响的,这样的话,缓存的命中率和可用率都会有相当的提升。
Q2: 这个缓存方案是怎么实现的?
这个说来有点话长,有空再说。我把mr 贴出来 有空看下 :https://git.baijia.com/weishi-cloud/weishi-toolkit-common/-/merge_requests/19
简而言之,是进行了查询 的关联sql 解析, 关联sql key 和 id又做了二层映射,达到删除时候能同步删查询缓存的效果
Q3: 这个缓存方案是否可靠?
本人在本地进行了多轮自测,迭代修复了一些小问题,目前已经是相对稳定状态了,后续把这个缓存查询的性能提升效果 同步在该Question 下面,所有的性能优化,在流量量级没有达到一定的情况下,比较难以看出其效果,但是做性能优化这件事,是有其价值的。