基于JetCache –单Entity缓存 查询增强的一种方式

 

 

直接入主题,先说引用和使用方法

 

引用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 关联的 条件查询缓存

 

上述使用都是基于分布式缓存通知,无需担心,多台机器造成缓存不一致问题

 

基本使用已经说完, 使用基本是黑盒无感知的。

 

 

使用场景

  1. 在条件查询比较多需要查询单体Entity(单张表特定数据) 会比较有效
  2. 读多写少的场景,一般来说 读写比例在 或超过八比一 都可以认为是读多写少,一般互联网创作者创造资源,用户读取资源, 都是读多写少场景,操纵资源的次数较少

   

优缺点

  1. 优点

能带来显著的查询缓存能力增强, 对于热点数据的条件查询,性能提升巨大

无需手动管理 查询缓存和 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 下面,所有的性能优化,在流量量级没有达到一定的情况下,比较难以看出其效果,但是做性能优化这件事,是有其价值的。

 

 

 

    

 

 

 

 

 

 


版权声明:本文为dongjijiaoxiangqu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。