首页  >  问答  >  正文

java - Mybatis 数据库多表关联分页的问题

举个例子:
有两个实体类 User 和 Address

public class User {
    private int id;
    private String username; // 用户名
    private List<Address> addresses;
    // getter setter...
}

public class Address {
    private int id;
    private String detail; // 详细地址
    private User user;    //所属用户
    // getter setter...
}

数据库:

create table t_user(
    id int(10) primary key auto_increment,
    username varchar(50)
);


create table t_address(
    id int(10) primary key auto_increment,
    detail varchar(255),
    user_id int(10),
    CONSTRAINT FOREIGN KEY (user_id) REFERENCES t_user(id)
);

mybatis映射配置:


<?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="org.mkh.shop.model.User">
    <resultMap type="User" id="userMap" autoMapping="true">
        <id property="id" column="u_id"/>
        <collection property="address" ofType="Address">
            <id property="id" column="a_id"/>
            <result property="detail" column="detail"/>
        </collection>
    </resultMap>

    <select id="find" resultType="User" parameterType="map">
        select  *,
                ta.id as 'a_id',
                tu.id as 'u_id' 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
        <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
        <if test="sort != null">
            order by ${sort} 
            <choose>
                <when test="order != null">${order}</when>
                <otherwise>asc</otherwise>
            </choose> 
        </if>
        limit #{pageOffset},#{pageSize}
    </select>
    
    <select id="find_count" resultType="int" parameterType="map">
        select count(*) 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
        <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
    </select>    
</mapper> 

用户和地址的关系为:一个用户有多个地址,一个地址只能属于一个用户,一对多
假设现在的需求是,分页查询用户,用表格显示,并把每个用户的所有地址显示出来
那么问题来了
按照上面的查询返回的分页的数据是没有问题的,但是分页的总记录数却是不对的。
比如查出来的数据(数据库数据,并非页面显示)如下:

u_id username a_id detail
1 user1 1 北京市海淀区
1 user1 2 北京市朝阳区
2 user2 3 天津市

因为我的需求是分页显示用户,所以一个用户就是一条数据在页面显示大概是这样子,理论上是两条数据,

用户id 用户名 地址
1 user1 1. 北京市海淀区 2. 北京市朝阳区
2 user2 1. 天津市
共1页,共2条数据,每页显示10条

但是,按mybatis的find_count配置 查出来是3条,这种问题如何解决?
查询count(*)的时候将所有left join 后面关联的表去除吗?这样会不会导致返回的数据不准确


补充说明:感觉大家是理解错我的意思了,其实我这个问题主要是在SQL 上,而不再mybatis上,因为我查询出来的数据映射完毕之后是完全没有问题的,只是在分页的总记录数上出现了问题,导致分页不正确

黄舟黄舟2660 天前1460

全部回复(6)我来回复

  • 漂亮男人

    漂亮男人2017-06-10 09:51:39

    刚才写了个例子测了一下

    `

    两个实体类
    public class User {

    
    private int id;
    private String username; // 用户名
    private List<Address> addresses;
    

    public class Address {

    private int id;
    private String detail; // 详细地址
    private int user_id; // 所属用户
    

    映射文件
    <resultMap type="com.atguigu.mybatis.entity.User" id="userMap" autoMapping="true">

        <result property="id" column="u_id"/>
        <collection property="addresses" ofType="com.atguigu.mybatis.entity.Address" autoMapping="true">
            <result property="id" column="a_id"/>
            <result property="user_id" column="u_id"/>
        </collection>
    </resultMap>
    
    <select id="select_all_user_address"  resultMap="userMap" >

    <!-- select tu.,ta., -->
    <!-- ta.id as 'a_id', -->
    <!-- tu.id as 'u_id' -->
    <!-- from t_user tu , -->
    <!-- t_address ta where ta.user_id=tu.id -->

            
             select   tu.*,ta.*,
                ta.id as 'a_id',
                tu.id as 'u_id' 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
    </select>
    

    测试结果

    封装成的 List<User>的size是没问题的

    回复
    0
  • ringa_lee

    ringa_lee2017-06-10 09:51:39

    关键词group by 自己查一下具体操作

    回复
    0
  • 欧阳克

    欧阳克2017-06-10 09:51:39

    SELECT 
        *, ta.id AS 'a_id', tu.id AS 'u_id'
    FROM
        t_user tu
            LEFT JOIN
        t_address ta ON ta.user_id = tu.id;

    你希望想要两条 但是你的sql查出三条,所以显示错误,
    应该拆分逻辑:
    应该先查出你想要的用户

    <select id="find" resultType="User" parameterType="map">
            select  *
            from t_user tu 
            <where> 
                <if test="name != null">
                    (username like #{name})
                </if>
            </where>
            <if test="sort != null">
                order by ${sort} 
                <choose>
                    <when test="order != null">${order}</when>
                    <otherwise>asc</otherwise>
                </choose> 
            </if>
            limit #{pageOffset},#{pageSize}
        </select>

    然后在

        <resultMap type="User" id="userMap" autoMapping="true">
            <id property="id" column="u_id"/>
            <collection " property="addresses" javaType= "ArrayList" column="u_id"
     ofType="Address" select= "??" />
        </resultMap>

    ??是自己实现个 用userId查List<Address>的方法

    回复
    0
  • 欧阳克

    欧阳克2017-06-10 09:51:39

    这种情况不能这么分页,你需要对主表数据进行分页。

    本来查询出100条数据,由于一对多会折叠去重很多数据,导致实际结果少于100条。

    这种情况下可以采取嵌套查询方式解决,就是需要N+1次执行,可以懒加载。

    或者看这里:https://my.oschina.net/flags/...

    有关 MyBatis 内容可以访问:http://mybatis.tk

    回复
    0
  • 扔个三星炸死你

    扔个三星炸死你2017-06-10 09:51:39

    <select id="find_count" resultType="int" parameterType="map">
        select count(*) 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
        <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
    </select> 

    改:

    <select id="find_count" resultType="int" parameterType="map">
        select count(*) 
        from t_user tu
       <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
    
        group by username
    </select> 
    

    回复
    0
  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-06-10 09:51:39

    用子查询就不会有问题了

    select count(*) from (
       // query 在这里即使关联100张表, 也不可能存在问题
    )

    楼主可以看一下Mybatis-PageHelper count sql 转换实现

    建议楼主直接使用 Mybatis-PageHelper 实现分页

    回复
    0
  • 取消回复