Ruoyi-vue-plus-5.x第二篇MyBatis-Plus数据持久层技术:2.2 分页与性能优化

发布于:2025-09-01 ⋅ 阅读:(20) ⋅ 点赞:(0)

👋 大家好,我是 阿问学长!专注于分享优质开源项目解析、毕业设计项目指导支持、幼小初高教辅资料推荐等,欢迎关注交流!🚀

分页与性能优化

前言

在企业级应用中,数据分页和性能优化是数据访问层的重要组成部分。MyBatis-Plus提供了强大的分页插件和多种性能优化策略。RuoYi-Vue-Plus框架充分利用了这些特性,实现了高效的数据分页和查询优化。本文将深入探讨MyBatis-Plus的分页机制、性能优化技巧以及在实际项目中的应用。

PaginationInterceptor分页插件

分页插件配置

在RuoYi-Vue-Plus中,分页插件的配置如下:

@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 设置数据库类型
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(500L);
        // 溢出总页数后是否进行处理
        paginationInnerInterceptor.setOverflow(true);
        // 生成 countSql 优化掉 join 现在只支持 left join
        paginationInnerInterceptor.setOptimizeJoin(true);
        
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        
        // 多租户插件
        TenantLineInnerInterceptor tenantLineInnerInterceptor = new TenantLineInnerInterceptor();
        tenantLineInnerInterceptor.setTenantLineHandler(tenantLineHandler());
        interceptor.addInnerInterceptor(tenantLineInnerInterceptor);
        
        // 数据权限插件
        DataPermissionInterceptor dataPermissionInterceptor = new DataPermissionInterceptor();
        dataPermissionInterceptor.setDataPermissionHandler(dataPermissionHandler());
        interceptor.addInnerInterceptor(dataPermissionInterceptor);
        
        // 乐观锁插件
        OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
        
        // 阻断插件
        BlockAttackInnerInterceptor blockAttackInnerInterceptor = new BlockAttackInnerInterceptor();
        interceptor.addInnerInterceptor(blockAttackInnerInterceptor);
        
        return interceptor;
    }
    
    /**
     * 分页插件自定义参数
     */
    @Bean
    @ConditionalOnMissingBean
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 分页合理化
        paginationInnerInterceptor.setOverflow(true);
        // 单页分页条数限制
        paginationInnerInterceptor.setMaxLimit(500L);
        // 数据库类型
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        return paginationInnerInterceptor;
    }
}

分页查询基础用法

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
    
    /**
     * 基础分页查询
     */
    public Page<SysUser> selectUserPage(int current, int size, SysUser user) {
        // 创建分页对象
        Page<SysUser> page = new Page<>(current, size);
        
        // 构建查询条件
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(user.getUserName()), 
                    SysUser::getUserName, user.getUserName());
        wrapper.eq(StringUtils.isNotBlank(user.getStatus()), 
                  SysUser::getStatus, user.getStatus());
        wrapper.orderByDesc(SysUser::getCreateTime);
        
        // 执行分页查询
        return baseMapper.selectPage(page, wrapper);
    }
    
    /**
     * 自定义分页查询
     */
    public Page<SysUserVo> selectPageUserList(PageQuery pageQuery, SysUserBo user) {
        LambdaQueryWrapper<SysUser> lqw = buildQueryWrapper(user);
        Page<SysUserVo> result = baseMapper.selectPageUserList(pageQuery.build(), lqw);
        return result;
    }
    
    /**
     * 不查询总数的分页
     */
    public Page<SysUser> selectUserPageWithoutCount(int current, int size, SysUser user) {
        // 创建分页对象,不查询总数
        Page<SysUser> page = new Page<>(current, size, false);
        
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(user.getUserName()), 
                    SysUser::getUserName, user.getUserName());
        
        return baseMapper.selectPage(page, wrapper);
    }
}

Page对象与分页参数

分页参数封装

/**
 * 分页查询实体类
 */
@Data
public class PageQuery {
    
    /**
     * 分页大小
     */
    @NotNull(message = "分页大小不能为空")
    @Min(value = 1, message = "分页大小最小值为 1")
    @Max(value = 100, message = "分页大小最大值为 100")
    private Integer pageSize;
    
    /**
     * 当前页数
     */
    @NotNull(message = "页码不能为空")
    @Min(value = 1, message = "页码最小值为 1")
    private Integer pageNum;
    
    /**
     * 排序列
     */
    private String orderByColumn;
    
    /**
     * 排序的方向desc或者asc
     */
    private String isAsc;
    
    /**
     * 当前记录起始索引 默认值
     */
    public static final int DEFAULT_PAGE_NUM = 1;
    
    /**
     * 每页显示记录数 默认值 默认查询所有
     */
    public static final int DEFAULT_PAGE_SIZE = 20;
    
    /**
     * 构建分页对象
     */
    public <T> Page<T> build() {
        Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
        Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
        
        if (pageNum <= 0) {
            pageNum = DEFAULT_PAGE_NUM;
        }
        
        Page<T> page = new Page<>(pageNum, pageSize);
        
        // 处理排序
        List<OrderItem> orderItems = buildOrderItem();
        if (CollUtil.isNotEmpty(orderItems)) {
            page.addOrder(orderItems);
        }
        
        return page;
    }
    
    /**
     * 构建排序
     */
    private List<OrderItem> buildOrderItem() {
        if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) {
            return Collections.emptyList();
        }
        
        String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
        orderBy = StringUtils.toUnderScoreCase(orderBy);
        
        // 兼容前端排序类型
        isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"});
        
        OrderItem orderItem = new OrderItem();
        orderItem.setColumn(orderBy);
        orderItem.setAsc("asc".equals(isAsc));
        
        return Collections.singletonList(orderItem);
    }
}

分页结果封装

/**
 * 表格分页数据对象
 */
@Data
public class TableDataInfo<T> implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    /**
     * 总记录数
     */
    private long total;
    
    /**
     * 列表数据
     */
    private List<T> rows;
    
    /**
     * 消息状态码
     */
    private int code;
    
    /**
     * 消息内容
     */
    private String msg;
    
    /**
     * 分页
     */
    public static <T> TableDataInfo<T> build(Page<T> page) {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(page.getRecords());
        rspData.setTotal(page.getTotal());
        return rspData;
    }
    
    public static <T> TableDataInfo<T> build(List<T> list) {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(list);
        rspData.setTotal(list.size());
        return rspData;
    }
    
    public static <T> TableDataInfo<T> build() {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(Collections.emptyList());
        rspData.setTotal(0);
        return rspData;
    }
}

Controller层分页使用

@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController {
    
    @Autowired
    private ISysUserService userService;
    
    /**
     * 获取用户列表
     */
    @SaCheckPermission("system:user:list")
    @GetMapping("/list")
    public TableDataInfo<SysUserVo> list(SysUserBo user, PageQuery pageQuery) {
        return userService.selectPageUserList(user, pageQuery);
    }
    
    /**
     * 导出用户列表
     */
    @SaCheckPermission("system:user:export")
    @PostMapping("/export")
    public void export(SysUserBo user, HttpServletResponse response) {
        List<SysUserVo> list = userService.selectUserList(user);
        ExcelUtil.exportExcel(list, "用户数据", SysUserVo.class, response);
    }
}

自定义分页SQL优化

复杂查询分页优化

@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
    
    /**
     * 自定义分页查询 - 关联查询优化
     */
    @Select("""
        <script>
        SELECT 
            u.user_id, u.user_name, u.nick_name, u.email, u.phonenumber,
            u.sex, u.avatar, u.status, u.create_time, u.remark,
            d.dept_name, d.leader
        FROM sys_user u
        LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
        <where>
            u.del_flag = '0'
            <if test="queryWrapper.sqlSegment != null and queryWrapper.sqlSegment != ''">
                AND ${queryWrapper.sqlSegment}
            </if>
        </where>
        ORDER BY u.create_time DESC
        </script>
        """)
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id"),
        @DataColumn(key = "userName", value = "u.user_id")
    })
    Page<SysUserVo> selectPageUserList(@Param("page") Page<SysUser> page, 
                                      @Param("queryWrapper") Wrapper<SysUser> queryWrapper);
    
    /**
     * 统计查询优化
     */
    @Select("""
        SELECT 
            COUNT(DISTINCT u.user_id) as total,
            COUNT(CASE WHEN u.status = '0' THEN 1 END) as activeCount,
            COUNT(CASE WHEN u.status = '1' THEN 1 END) as inactiveCount
        FROM sys_user u
        LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
        WHERE u.del_flag = '0'
        ${ew.customSqlSegment}
        """)
    UserStatisticsVo selectUserStatistics(@Param("ew") Wrapper<SysUser> queryWrapper);
    
    /**
     * 大数据量分页查询优化 - 使用子查询
     */
    @Select("""
        SELECT u.*, d.dept_name 
        FROM sys_user u
        LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
        WHERE u.user_id IN (
            SELECT user_id FROM (
                SELECT user_id FROM sys_user 
                WHERE del_flag = '0' 
                ${ew.customSqlSegment}
                LIMIT #{page.offset}, #{page.size}
            ) temp
        )
        ORDER BY u.create_time DESC
        """)
    List<SysUserVo> selectPageUserListOptimized(@Param("page") Page<SysUser> page, 
                                               @Param("ew") Wrapper<SysUser> queryWrapper);
}

分页性能监控

@Component
public class PagePerformanceInterceptor implements Interceptor {
    
    private static final Logger log = LoggerFactory.getLogger(PagePerformanceInterceptor.class);
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        try {
            Object result = invocation.proceed();
            
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            
            // 记录慢查询
            if (executionTime > 1000) { // 超过1秒的查询
                MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
                String sqlId = mappedStatement.getId();
                log.warn("慢查询检测: SQL ID: {}, 执行时间: {}ms", sqlId, executionTime);
                
                // 发送告警
                sendSlowQueryAlert(sqlId, executionTime);
            }
            
            return result;
            
        } catch (Exception e) {
            log.error("SQL执行异常", e);
            throw e;
        }
    }
    
    private void sendSlowQueryAlert(String sqlId, long executionTime) {
        // 实现告警逻辑
        SlowQueryAlert alert = new SlowQueryAlert();
        alert.setSqlId(sqlId);
        alert.setExecutionTime(executionTime);
        alert.setTimestamp(new Date());
        
        // 异步发送告警
        AsyncManager.me().execute(() -> {
            alertService.sendSlowQueryAlert(alert);
        });
    }
    
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    
    @Override
    public void setProperties(Properties properties) {
        // 设置属性
    }
}

大数据量分页性能调优

深分页优化策略

@Service
public class LargeDataPageService {
    
    @Autowired
    private SysUserMapper userMapper;
    
    /**
     * 传统分页 - 性能较差
     */
    public Page<SysUser> traditionalPage(int pageNum, int pageSize) {
        Page<SysUser> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getDelFlag, "0");
        wrapper.orderByDesc(SysUser::getCreateTime);
        
        return userMapper.selectPage(page, wrapper);
    }
    
    /**
     * 游标分页 - 适用于大数据量
     */
    public List<SysUser> cursorPage(Long lastId, int pageSize) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getDelFlag, "0");
        
        if (lastId != null) {
            wrapper.lt(SysUser::getUserId, lastId);
        }
        
        wrapper.orderByDesc(SysUser::getUserId);
        wrapper.last("LIMIT " + pageSize);
        
        return userMapper.selectList(wrapper);
    }
    
    /**
     * 基于时间的游标分页
     */
    public List<SysUser> timeCursorPage(Date lastCreateTime, int pageSize) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getDelFlag, "0");
        
        if (lastCreateTime != null) {
            wrapper.lt(SysUser::getCreateTime, lastCreateTime);
        }
        
        wrapper.orderByDesc(SysUser::getCreateTime);
        wrapper.last("LIMIT " + pageSize);
        
        return userMapper.selectList(wrapper);
    }
    
    /**
     * 子查询优化分页
     */
    public Page<SysUserVo> optimizedPage(int pageNum, int pageSize, SysUserBo user) {
        // 先查询ID列表
        Page<Long> idPage = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<SysUser> idWrapper = new LambdaQueryWrapper<>();
        idWrapper.select(SysUser::getUserId);
        idWrapper.eq(SysUser::getDelFlag, "0");
        
        // 添加查询条件
        if (StringUtils.isNotBlank(user.getUserName())) {
            idWrapper.like(SysUser::getUserName, user.getUserName());
        }
        if (StringUtils.isNotBlank(user.getStatus())) {
            idWrapper.eq(SysUser::getStatus, user.getStatus());
        }
        
        idWrapper.orderByDesc(SysUser::getCreateTime);
        
        Page<SysUser> idResult = userMapper.selectPage(idPage, idWrapper);
        
        if (CollUtil.isEmpty(idResult.getRecords())) {
            return new Page<>(pageNum, pageSize, 0);
        }
        
        // 根据ID列表查询完整数据
        List<Long> userIds = idResult.getRecords().stream()
            .map(SysUser::getUserId)
            .collect(Collectors.toList());
        
        List<SysUserVo> userList = userMapper.selectUserListByIds(userIds);
        
        // 构建分页结果
        Page<SysUserVo> result = new Page<>(pageNum, pageSize, idResult.getTotal());
        result.setRecords(userList);
        
        return result;
    }
    
    /**
     * 缓存分页结果
     */
    @Cacheable(value = "userPage", key = "#pageNum + '_' + #pageSize + '_' + #user.hashCode()")
    public Page<SysUserVo> cachedPage(int pageNum, int pageSize, SysUserBo user) {
        return selectPageUserList(pageNum, pageSize, user);
    }
    
    /**
     * 异步预加载下一页
     */
    @Async
    public CompletableFuture<Page<SysUserVo>> preloadNextPage(int currentPage, int pageSize, SysUserBo user) {
        int nextPage = currentPage + 1;
        Page<SysUserVo> nextPageData = selectPageUserList(nextPage, pageSize, user);
        
        // 缓存下一页数据
        String cacheKey = "userPage:" + nextPage + "_" + pageSize + "_" + user.hashCode();
        redisTemplate.opsForValue().set(cacheKey, nextPageData, Duration.ofMinutes(5));
        
        return CompletableFuture.completedFuture(nextPageData);
    }
}

索引优化建议

-- 用户表索引优化
-- 1. 主键索引(自动创建)
ALTER TABLE sys_user ADD PRIMARY KEY (user_id);

-- 2. 唯一索引
ALTER TABLE sys_user ADD UNIQUE INDEX uk_user_name (user_name);
ALTER TABLE sys_user ADD UNIQUE INDEX uk_phone (phonenumber);
ALTER TABLE sys_user ADD UNIQUE INDEX uk_email (email);

-- 3. 普通索引
ALTER TABLE sys_user ADD INDEX idx_dept_id (dept_id);
ALTER TABLE sys_user ADD INDEX idx_status (status);
ALTER TABLE sys_user ADD INDEX idx_create_time (create_time);
ALTER TABLE sys_user ADD INDEX idx_del_flag (del_flag);

-- 4. 复合索引(根据查询条件组合)
ALTER TABLE sys_user ADD INDEX idx_status_dept_create (status, dept_id, create_time);
ALTER TABLE sys_user ADD INDEX idx_del_status_create (del_flag, status, create_time);

-- 5. 覆盖索引(包含查询所需的所有字段)
ALTER TABLE sys_user ADD INDEX idx_cover_list (del_flag, status, dept_id, user_id, user_name, nick_name, create_time);

-- 6. 分页查询优化索引
ALTER TABLE sys_user ADD INDEX idx_page_optimize (del_flag, create_time, user_id);

分页缓存策略

@Service
public class PageCacheService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String PAGE_CACHE_PREFIX = "page:cache:";
    private static final Duration CACHE_DURATION = Duration.ofMinutes(10);
    
    /**
     * 获取分页缓存
     */
    public <T> Page<T> getPageCache(String cacheKey, Class<T> clazz) {
        try {
            Object cached = redisTemplate.opsForValue().get(PAGE_CACHE_PREFIX + cacheKey);
            if (cached != null) {
                return (Page<T>) cached;
            }
        } catch (Exception e) {
            log.warn("获取分页缓存失败: {}", e.getMessage());
        }
        return null;
    }
    
    /**
     * 设置分页缓存
     */
    public <T> void setPageCache(String cacheKey, Page<T> page) {
        try {
            redisTemplate.opsForValue().set(PAGE_CACHE_PREFIX + cacheKey, page, CACHE_DURATION);
        } catch (Exception e) {
            log.warn("设置分页缓存失败: {}", e.getMessage());
        }
    }
    
    /**
     * 清除分页缓存
     */
    public void clearPageCache(String pattern) {
        try {
            Set<String> keys = redisTemplate.keys(PAGE_CACHE_PREFIX + pattern + "*");
            if (CollUtil.isNotEmpty(keys)) {
                redisTemplate.delete(keys);
            }
        } catch (Exception e) {
            log.warn("清除分页缓存失败: {}", e.getMessage());
        }
    }
    
    /**
     * 智能分页缓存
     */
    public <T> Page<T> smartPageCache(String baseKey, Supplier<Page<T>> pageSupplier) {
        String cacheKey = generateCacheKey(baseKey);
        
        // 尝试从缓存获取
        Page<T> cachedPage = getPageCache(cacheKey, null);
        if (cachedPage != null) {
            return cachedPage;
        }
        
        // 缓存未命中,执行查询
        Page<T> page = pageSupplier.get();
        
        // 只缓存前几页的数据
        if (page.getCurrent() <= 5) {
            setPageCache(cacheKey, page);
        }
        
        return page;
    }
    
    private String generateCacheKey(String baseKey) {
        // 生成缓存键的逻辑
        return baseKey + ":" + System.currentTimeMillis() / (5 * 60 * 1000); // 5分钟为一个时间段
    }
}

分页查询最佳实践

分页参数校验

@Component
public class PageValidator {
    
    private static final int MAX_PAGE_SIZE = 500;
    private static final int DEFAULT_PAGE_SIZE = 20;
    
    /**
     * 校验分页参数
     */
    public PageQuery validatePageQuery(PageQuery pageQuery) {
        if (pageQuery == null) {
            pageQuery = new PageQuery();
        }
        
        // 校验页码
        if (pageQuery.getPageNum() == null || pageQuery.getPageNum() < 1) {
            pageQuery.setPageNum(1);
        }
        
        // 校验页大小
        if (pageQuery.getPageSize() == null || pageQuery.getPageSize() < 1) {
            pageQuery.setPageSize(DEFAULT_PAGE_SIZE);
        }
        
        if (pageQuery.getPageSize() > MAX_PAGE_SIZE) {
            pageQuery.setPageSize(MAX_PAGE_SIZE);
        }
        
        // 校验排序字段
        if (StringUtils.isNotBlank(pageQuery.getOrderByColumn())) {
            String orderBy = SqlUtil.escapeOrderBySql(pageQuery.getOrderByColumn());
            pageQuery.setOrderByColumn(orderBy);
        }
        
        return pageQuery;
    }
    
    /**
     * 检查是否为深分页
     */
    public boolean isDeepPaging(PageQuery pageQuery) {
        return pageQuery.getPageNum() * pageQuery.getPageSize() > 10000;
    }
    
    /**
     * 深分页警告
     */
    public void warnDeepPaging(PageQuery pageQuery, String operation) {
        if (isDeepPaging(pageQuery)) {
            log.warn("深分页查询警告: 操作={}, 页码={}, 页大小={}, 偏移量={}", 
                    operation, pageQuery.getPageNum(), pageQuery.getPageSize(),
                    pageQuery.getPageNum() * pageQuery.getPageSize());
        }
    }
}

分页性能监控

@Aspect
@Component
public class PagePerformanceAspect {
    
    private static final Logger log = LoggerFactory.getLogger(PagePerformanceAspect.class);
    
    @Around("execution(* *..*Service.selectPage*(..))")
    public Object monitorPageQuery(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        
        try {
            Object result = joinPoint.proceed();
            
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            
            // 记录分页查询性能
            logPagePerformance(methodName, args, executionTime, result);
            
            return result;
            
        } catch (Exception e) {
            log.error("分页查询异常: method={}, args={}", methodName, args, e);
            throw e;
        }
    }
    
    private void logPagePerformance(String methodName, Object[] args, long executionTime, Object result) {
        if (result instanceof Page) {
            Page<?> page = (Page<?>) result;
            
            // 记录性能指标
            PagePerformanceMetrics metrics = new PagePerformanceMetrics();
            metrics.setMethodName(methodName);
            metrics.setExecutionTime(executionTime);
            metrics.setPageNum(page.getCurrent());
            metrics.setPageSize(page.getSize());
            metrics.setTotal(page.getTotal());
            metrics.setRecordCount(page.getRecords().size());
            
            // 慢查询告警
            if (executionTime > 2000) {
                log.warn("分页查询性能告警: {}", metrics);
                sendPerformanceAlert(metrics);
            } else {
                log.debug("分页查询性能: {}", metrics);
            }
        }
    }
    
    private void sendPerformanceAlert(PagePerformanceMetrics metrics) {
        // 发送性能告警
        AsyncManager.me().execute(() -> {
            performanceAlertService.sendPagePerformanceAlert(metrics);
        });
    }
}

/**
 * 分页性能指标
 */
@Data
public class PagePerformanceMetrics {
    private String methodName;
    private long executionTime;
    private long pageNum;
    private long pageSize;
    private long total;
    private int recordCount;
    private Date timestamp = new Date();
}

总结

本文深入介绍了MyBatis-Plus的分页与性能优化,包括:

  1. 分页插件配置:PaginationInnerInterceptor的详细配置和使用
  2. 分页对象使用:Page对象、PageQuery参数封装、TableDataInfo结果封装
  3. 自定义分页SQL:复杂查询的分页优化策略
  4. 大数据量优化:深分页问题的解决方案,包括游标分页、子查询优化等
  5. 性能监控:分页查询的性能监控和告警机制
  6. 最佳实践:分页参数校验、缓存策略、索引优化等

通过这些优化策略,可以显著提升大数据量场景下的分页查询性能,为用户提供更好的使用体验。

在下一篇文章中,我们将探讨MyBatis-Plus的多租户与数据权限功能。

参考资料


网站公告

今日签到

点亮在社区的每一天
去签到