前言

工作采坑记录: mabtis-plus分页列表records.size() 和 total 数量不一致问题。


一、total和records.size()数量不一致原因。

mybatis-plus3.2.0的版本在用mabatis-plus 一对多查询做关联查询时,前段传递的参数pagesize是在你sql关联之后的语句最后加上limit,则在对多的情况下,可能主表数据关联子表后同一条主表对应多条子表记录,但是在映射后只会返回一条主表信息,但是total计算的是关联后的总数量。接下来我将举例说明。

二、示例

1 代码

1.1 pom

  <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>

1.2 分页插件配置

@Configuration
public class DateSourceConfig {
    /**
     * 注册分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

1.3 实体

@Data
@TableName("t_class")
public class ClassDO {
    /**
     * 类id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long classId;
    private String className;
}


@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Long classId;
}

1.4 controller

@RestController
@RequestMapping("/class")
@AllArgsConstructor
public class ClassController {
    private final ClassMapper classMapper;
    @GetMapping("page")
    public R page(QueryRequest request, User user){
        Page<User> page = new Page<>(request.getPageNum(), request.getPageSize());
        IPage<ClassVO> resultPage = classMapper.page(page, user);
        return R.ok(resultPage);
    }
}

1.5 mapper

public interface ClassMapper extends BaseMapper<ClassDO> {
    IPage<ClassVO> page(Page<User> page, User user);
}

<mapper namespace="com.lfh.demo.mapper.ClassMapper">

    <resultMap id="pageMap" type="com.lfh.demo.entity.vo.ClassVO">
        <result column="classId" property="classId"/>
        <result column="className" property="className"/>
        <collection property="userList" ofType="com.lfh.demo.entity.User" javaType="ArrayList">
            <result column="userName" property="name"/>
        </collection>
    </resultMap>
    <select id="page" resultMap="pageMap">
        select tc.id as classId, tc.class_name as className,
            tu.name as userName
        from t_class tc
        left join t_user  tu on tu.class_id = tc.id
    </select>
</mapper>

2 测试结果

{
    "code": 0,
    "data": {
        "records": [
            {
                "classId": 1,
                "className": "一年级一班",
                "userList": [
                    {
                        "id": null,
                        "name": "张六",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "张大",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "王五",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "李四",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "张三",
                        "age": null,
                        "email": null,
                        "classId": null
                    }
                ]
            },
            {
                "classId": 2,
                "className": "一年级二班",
                "userList": []
            },
            {
                "classId": 3,
                "className": "一年级三班",
                "userList": []
            }
        ],
        "total": 7,
        "size": 10,
        "current": 1,
        "orders": [],
        "searchCount": true,
        "pages": 1
    },
    "msg": "执行成功"
}

由测试结果可看除返回的total是计算子表的数据 而实际我们需要的是返回几个班级的数量即可。

3 解决方案

3.1 升级mybatis-plus的版本

3. 1.1 修改pom文件

讲mybatis-plus-boot-starter的版本升级到3.4.1

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
3.1.2 修改分页插件的配置文件

@Configuration
public class DateSourceConfig {
    /**
     * 注册分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
3.1.3 测试结果
{
    "code": 0,
    "data": {
        "records": [
            {
                "classId": 1,
                "className": "一年级一班",
                "userList": [
                    {
                        "id": null,
                        "name": "张六",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "张大",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "王五",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "李四",
                        "age": null,
                        "email": null,
                        "classId": null
                    },
                    {
                        "id": null,
                        "name": "张三",
                        "age": null,
                        "email": null,
                        "classId": null
                    }
                ]
            },
            {
                "classId": 2,
                "className": "一年级二班",
                "userList": []
            },
            {
                "classId": 3,
                "className": "一年级三班",
                "userList": []
            }
        ],
        "total": 3,
        "size": 10,
        "current": 1,
        "orders": [],
        "optimizeCountSql": true,
        "hitCount": false,
        "countId": null,
        "maxLimit": null,
        "searchCount": true,
        "pages": 1
    },
    "msg": "执行成功"
}

可以看出返回的total是正确的数量

3.2 修改mapper.xml的查询语句,通过子查询也可解决

3.2.1 修改mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lfh.demo.mapper.ClassMapper">

    <resultMap id="pageMap" type="com.lfh.demo.entity.vo.ClassVO">
        <result column="classId" property="classId"/>
        <result column="className" property="className"/>
        <collection column="classId" property="userList" ofType="com.lfh.demo.entity.User" javaType="ArrayList" select="selectUserByClassId">
            <result column="userName" property="name"/>
        </collection>
    </resultMap>
    <select id="selectUserByClassId" resultType="com.lfh.demo.entity.User">
        select * from t_user where class_id = #{classId}
    </select>
    <select id="page" resultMap="pageMap">
        select tc.id as classId, tc.class_name as className
        from t_class tc
    </select>
</mapper>
3.2.2 测试结果
{
    "code": 0,
    "data": {
        "records": [
            {
                "classId": 1,
                "className": "一年级一班",
                "userList": [
                    {
                        "id": 2,
                        "name": "张三",
                        "age": 19,
                        "email": null,
                        "classId": 1
                    },
                    {
                        "id": 3,
                        "name": "李四",
                        "age": 20,
                        "email": null,
                        "classId": 1
                    },
                    {
                        "id": 4,
                        "name": "王五",
                        "age": 51,
                        "email": null,
                        "classId": 1
                    },
                    {
                        "id": 5,
                        "name": "张大",
                        "age": 21,
                        "email": null,
                        "classId": 1
                    },
                    {
                        "id": 6,
                        "name": "张六",
                        "age": 22,
                        "email": null,
                        "classId": 1
                    }
                ]
            },
            {
                "classId": 2,
                "className": "一年级二班",
                "userList": []
            },
            {
                "classId": 3,
                "className": "一年级三班",
                "userList": []
            }
        ],
        "total": 3,
        "size": 10,
        "current": 1,
        "orders": [],
        "searchCount": true,
        "pages": 1
    },
    "msg": "执行成功"
}

total和数据的记录数一致

3.3 对返回记录进行重新封装(不推荐)

当前返回的记录拿到ipage之后直接进行返回的。可以通过工具类对结果集进行处理后返回。

/**
     * 封装前端分页表格所需数据
     *
     * @param pageInfo pageInfo
     * @return Map<String, Object>
     */
    public static Map<String, Object> getDataTable(IPage<?> pageInfo) {
        Map data = new ConcurrentHashMap<String, Object>(2);
        data.put("records", pageInfo.getRecords());
        data.put("total", pageInfo.getTotal());
        return data;
    }

通过对ipage处理后重新返回,虽然total和结果集能对应的上 但是还存在一个问题就是返回的分页数据可能是和前端一页暂时的条数不匹配的。打个比方:现在一个class对应10个user 这时mysql查到的数据为10条,但是通过mybatis对多映射之后到class实体类的时候其实只有一条数据,只是其字段userList的大小为10,那么我们返回到前端的结果也只是有一条数据在当前页,但是还有其他数据的情况下,点击下一页就会可能出现每页显示条数不一致的问题。用户体验稍差,但如果没这方便的要求,只是实现功能的话,这种方法也可行。

总结

以上则是几种分页数据total和records的数量不一致的解决方案,推荐第一种,当然此方法还是需要作者更新,另外存在版本冲突而无法更换mybatis-plus版本的话,就通过第二种的子查询的方式来实现。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐