支持连表等复杂查询的PageHelper修改

本文介绍了如何修改PageHelper以支持连表等复杂查询的分页,通过创建CustomDialect自定义方言,调整limit的位置,解决了PageHelper在复杂查询中分页的问题。详细步骤包括:添加CustomDialect,复写CustomPageHelper和CustomSqlUtil,配置改动,以及如何在实际使用中应用这些修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

新版本的PageHelper与mybatis请移步这里——支持PageHelper5.1.4 Mybatis3.4.6
先说说使用PageHelper踩过的坑:
- 在mapper映射文件中,如果使用了limit关键字,而又使用了PageHelper的功能,比如orderBy,那么就会报错。
- 在使用稍微复杂的查询时,PageHelper是针对最外层(最下方)的数据进行分页的。

出现这样的问题,归根结底还是PageHelper源码的问题。

这套修改的原理即是修改pagehelper “limit”的位置,从末尾改到我们想要的位置。

不多说PageHelper本身,本文使用的PageHelper版本为

         <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.2.1</version>
        </dependency>

这里以MySql为例,使得PageHelper支持复杂查询的分页。


一、添加CustomDialect,自定义方言

先看看原版的方言类的定义

package com.github.pagehelper.dialect;
    @Override
    public String getPageSql(String sql, Page page, RowBounds rowBounds, CacheKey pageKey) {
        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);
        sqlBuilder.append(sql);
        sqlBuilder.append(" limit ?,?");
        return sqlBuilder.toString();
    }

从这里可以看出,PageHelper在针对MySql数据库进行分页时,是在sql语句的最后加上limit偏移量进行分页查询的。且不说这种查询在数据量大时效率可能不高,这样去操作的话,在稍微复杂的查询中,通常无法正常的进行分页。

/**
 * Created by Anur IjuoKaruKas on 2017/9/28.
 * Description :
 */
public class CustomDialect extends MySqlDialect {
   
   

    public CustomDialect(SqlUtil sqlUtil) {
        super(sqlUtil);
    }

    @Override
    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {
        return super.processPageParameter(ms, paramMap, page, boundSql, pageKey);
    }

    @Override
    public String getPageSql(String sql, Page page, RowBounds rowBounds, CacheKey pageKey) {
        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);
        if (sql.indexOf(ProjectConstant.SQL_SIGN) != -1) {
            StringBuffer stringBuffer = new StringBuffer(sql);
            stringBuffer.indexOf(ProjectConstant.SQL_SIGN);

            StringBuffer mae = new StringBuffer(stringBuffer.substring(0, stringBuffer.indexOf(ProjectConstant.SQL_SIGN)));
            StringBuffer uShiRo = new StringBuffer(stringBuffer.substring(stringBuffer.indexOf(ProjectConstant.SQL_SIGN), sql.length()));

            mae.insert(mae.lastIndexOf(")")," limit ?,?");
            return mae.append(uShiRo).toString();
        }
        sqlBuilder.append(sql);
        sqlBuilder.append(" limit ?,?");
        return sqlBuilder.toString();
    }
}

所以,在这里,我对它进行了一点点的改写。

新建一个CustomDialect继承MySqlDialect,并重写了原方法。

在这里,做了一个判断,如果sql语句中包含 * ProjectConstant.SQL_SIGN(limitable) ,那么在这前面加上 “limit ?,?”*

这个SQL_SIGN是什么呢?

public static final String SQL_SIGN = "AS limitable";

实际上就是一个用于标记哪里需要使用偏移量的一个标识。

在mapper映射文件中就可以这样写:

    <select id="selectRecordByComplexCondition" resultMap="ListQueryMap" parameterMap="ListQueryPo">
        SELECT
        *
        from
        (
            SELECT
            *
            FROM
            record r
            WHERE
            r.record_release_state = 1
            <if test="tagIdListToSqlString!=null">
                AND r.record_id IN (
                SELECT
                object_id
                FROM
                record_tag rtag
                WHERE
                rtag.tag_id IN ${tagIdListToSqlString}
                AND rtag.module = #{moduleEnumIndex}
                GROUP BY
                rtag.object_id
                HAVING
                count(*) &gt;= #{tagCount}
                )
            </if>
            AND r.module = #{moduleEnumIndex}
            <if test="rcId!=null">
                AND r.rc_id = #{rcId}
            </if>
            <if test="raId!=null">
                AND r.ra_id = #{raId}
            </if>
            <if test="recordTitle!=null">
                AND r.record_title LIKE CONCAT(CONCAT('%', #{recordTitle}), '%')
            </if>
            <if test="recordReleaseTimeFrom!=null">
                AND r.record_release_time &gt; #{recordReleaseTimeFrom}
            </if>

    /* 现在的PageHelper limit 加在这里 */

            ) AS limitable
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值