记生产中一次Mybatis分页问题处理

418 阅读1分钟

问题描述:

我们有个列表,分页只有三页,接口返回条数也只有53条

代码跟到最后,发现列表有联合查询,并且是一对多关系,左连接,查出来对象中的某个属性是list。

代码如下:

Page<BusinessContentInfoVO> page = new Page<>(param.getPageInfo().getPageNum(), param.getPageInfo().getPageSize());
param.setAppIds(appIds);
page = contentInfoMapper.page(page, param);
public interface BusinessContentInfoMapper extends BaseMapper<BusinessContentInfo> {

    Page<BusinessContentInfoVO> page(Page<BusinessContentInfoVO> ipage, @Param("params") ContentInfoQO param);

    List<BusinessContentInfoVO> getallContentByUsableState();
}

BusinessContentInfoMapper.xml (部分省略)如下

<resultMap id="BaseResultVOMap"
    type="com.csp.microx.content.model.params.content.BusinessContentInfoVO">
    <id column="content_id" property="contentId" />
    <result column="content_title" property="contentTitle" />
	...
    <collection property="mediaStatus" ofType="com.csp.microx.content.model.params.content.BusinessContentInfoMediaStatusVO">
        <result column="channel_name" property="channelName"/>
        <result column="audit_status" property="auditStatus"/>
        <result column="app_channel_id" property="appChannelId"/>
    </collection>
</resultMap>

<select id="page" parameterType="com.csp.microx.content.model.params.content.ContentInfoQO"
    resultMap="BaseResultVOMap">
    SELECT
    c.*,
    channel.channel_name,channel.audit_status,channel.app_channel_id,t.puzzle_flag
    FROM
    business_content_info c
    LEFT JOIN business_app a ON c.app_id = a.id
    LEFT JOIN business_content_channel channel ON c.content_id = channel.content_id
    LEFT JOIN business_template_info t ON c.template_code = t.template_code
    <where>
        <if test="params.contentTitle !=null and params.contentTitle !=''">
            AND c.content_title like concat('%', #{params.contentTitle}, '%')
        </if>
        <if test="params.contentState !=null and params.contentState !=''">
            AND c.content_state = #{params.contentState}
        </if>
        <if test="params.businessBelong !=null and params.businessBelong !=''">
            AND c.business_belong = #{params.businessBelong}
        </if>
        <if test="params.beginTime !=null ">
            AND c.create_time &gt;= #{params.beginTime}
        </if>
        <if test="params.endTime !=null  ">
            AND c.create_time &lt;= #{params.endTime}
        </if>
    </where>
    order by c.create_time desc
</select>

如果没有分页,这种联合查询是没有问题的,business_content_info,主表确实只有53条数据,也没有问题,问题在于,查询第三页的时候,limit计算错误。

查询到的数据其实是连表查询的107条的第三页数据,所以导致接口查询不到全量数据。

解决方案

其实解决方法有好几种,最简单的一种,只需要修改BusinessContentInfoMapper.xml ,修改如下:

<resultMap id="BaseResultVOMap"
           type="com.csp.microx.content.model.params.content.BusinessContentInfoVO">
    <id column="content_id" property="contentId" />
    <result column="content_title" property="contentTitle" />
	...

    <collection property="mediaStatus" ofType="com.csp.microx.content.model.params.content.BusinessContentInfoMediaStatusVO"
                select="queryMediaList" column="content_id">
    </collection>
</resultMap>

<select id="queryMediaList" resultType="com.csp.microx.content.model.params.content.BusinessContentInfoMediaStatusVO">
    select channel.channel_name,channel.audit_status,channel.app_channel_id,channel.content_id
    from business_content_channel channel
    where channel.content_id = #{id}
</select>

<select id="page" parameterType="com.csp.microx.content.model.params.content.ContentInfoQO"
        resultMap="BaseResultVOMap">
    SELECT
    c.content_id, c.content_title, c.content_type, c.business_belong, c.body_text,
    c.create_time, c.creater, c.modify_time,
    c.content_state, c.audit_opinion, c.app_id, a.app_name,
    c.auditor, c.last_auditor,c.thumbnail,
    c.content_source, c.create_source,c.chatbotH5_url,t.puzzle_flag
    FROM
    business_content_info c
    LEFT JOIN business_app a ON c.app_id = a.id
    LEFT JOIN business_template_info t ON c.template_code = t.template_code
    <where>
        <if test="params.contentTitle !=null and params.contentTitle !=''">
            AND c.content_title like concat('%', #{params.contentTitle}, '%')
        </if>
        <if test="params.contentState !=null and params.contentState !=''">
            AND c.content_state = #{params.contentState}
        </if>
        <if test="params.businessBelong !=null and params.businessBelong !=''">
            AND c.business_belong = #{params.businessBelong}
        </if>
        <if test="params.beginTime !=null ">
            AND c.create_time &gt;= #{params.beginTime}
        </if>
        <if test="params.endTime !=null  ">
            AND c.create_time &lt;= #{params.endTime}
        </if>
    </where>
    order by c.create_time desc
</select>

因为项目中有成员有不良的修改方式,也能达到目标,将联查去掉,然后循环列表,再去查其他的子表。

这里面有个非常大的问题,在循环里面执行查询sql。影响数据库性能,影响接口响应速度。

但是非常不推荐,也不建议。