赞
踩
分页查询接口有两次查询:
SELECT * FROM sys_user LIMIT 1,20;
SELECT COUNT(*) FROM sys_user;
count查询需要一行行读数据,累加起来得到总量,效率很低。
一行语句,没有可优化空间,pass
查询LIMIT分页数据,靠前的数据一般都不慢,多线程增加代码复杂性,而且目前的问题是count耗时长,所以该方案也pass
简单可行,缺点是数据实时性不高,新增、删除的数量短期内不会更新,不适合用在高实时性的场景下
响应快,其原理是根据数据总大小和采样的行数据大小做计算得出的预估行数,这是一个近似值,不适合要求高精确度的场景
既然MySQL不中用,那就换其他的存储引擎,虽然解决了查询慢的问题,但是工作量激增
现在编写代码,写一个分页数量缓存工具类:PageCountCacheManager
实现内容:
提供缓存接口函数,支持设置缓存条件:查询时间超过指定值、查询数量超过指定值,当满足任一条件即可触发缓存机制。
直接贴代码:
import com.llp.utils.CacheUtil; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; /** * 分页查询的数据总量缓存器 * * @author llp * @date 2023-11-22 10:28 */ public class PageCountCacheManager { /** * 查询时间超过这个值就缓存,单位(秒) */ private static final long TIME = 5; /** * 查询数量超过这个值就缓存 */ private static final long AMOUNT = 100000; /** * 缓存过期时间,单位(秒) */ private static final long EXPIRE_TIME = 60; /** * 按查询时间来缓存,超过一定时间的查询就缓存起来 */ public static long cacheByTime(String key, Callable<Long> task) { key = "PageCount_Time_" + key; return run(key, task, true, false, false, TIME, 0, EXPIRE_TIME); } public static long cacheByTime(String key, Callable<Long> task, long time, long expireTime) { key = "PageCount_Time_" + key; return run(key, task, true, false, false, time, 0, expireTime); } /** * 按查询数量来缓存,超过一定数量的查询就缓存起来 */ public static long cacheByAmount(String key, Callable<Long> task) { key = "PageCount_Amount_" + key; return run(key, task, false, true, false, 0, AMOUNT, EXPIRE_TIME); } public static long cacheByAmount(String key, Callable<Long> task, long amount, long expireTime) { key = "PageCount_Amount_" + key; return run(key, task, false, true, false, 0, amount, expireTime); } /** * 结合查询时间和查询数量来缓存,当超过一定时间或一定数量就缓存起来 */ public static long cacheByBoth(String key, Callable<Long> task) { key = "PageCount_Both_" + key; return run(key, task, false, false, true, TIME, AMOUNT, EXPIRE_TIME); } public static long cacheByBoth(String key, Callable<Long> task, long time, long amount, long expireTime) { key = "PageCount_Both_" + key; return run(key, task, false, false, true, time, amount, expireTime); } /*************** 私有方法 ***************/ private static long run(String key, Callable<Long> task, boolean byTime, boolean byAmount, boolean byBoth, long time, long amount, long expireTime) { long start = System.currentTimeMillis(); // 查数据 Long result = null; try { result = task.call(); } catch (Exception e) { e.printStackTrace(); } // 查询结果为空,令其为0 if (result == null) { result = 0L; } if (byTime || byBoth) { // 判断时间 long executionTime = System.currentTimeMillis() - start; if (executionTime > time) { // 缓存数据 CacheUtil.set(key, result, expireTime, TimeUnit.SECONDS); } } if (byAmount || byBoth) { // 判断数量 if (result > amount) { // 缓存数据 CacheUtil.set(key, result, expireTime, TimeUnit.SECONDS); } } return result; } }
其中CacheUtil是缓存类,可以是JVM内缓存,也可以是RedisTemplate缓存,这个依项目而定
使用方式:
//这是Service的查询函数
@Override public long countByCondition(BaseCondition condition){
String key=this.getClass().getName();
return PageCountCacheManager.cacheByTime(key,()->mapper.countByCondition(condition));
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。