java - Mybatis 資料庫多表關聯分頁的問題
黄舟
黄舟 2017-06-10 09:49:39
0
6
1501

舉例:
有兩個實體類別 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上,因為我查詢出來的資料映射完畢之後是完全沒有問題的,只是在分頁的總記錄數上出現了問題,導致分頁不正確

#
黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回覆(6)
漂亮男人

剛才寫了個例子測了一下

`

兩個實體類別
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; // 所属用户

映射檔

    <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 
        left join t_address ta on ta.user_id=tu.id 
</select>

測試結果

封裝成的 List的size是沒問題的

左手右手慢动作

關鍵字group by 自己查一下具體操作

学霸
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

的方法
学霸

這種情況不能這麼分頁,你需要將主表資料分頁。

本來查詢出100條數據,由於一對多會折疊去重很多數據,導致實際結果少於100條。

這種情況下可以採取巢狀查詢方式解決,就是需要N+1次執行,可以懶載入。

或看這裡:https://my.oschina.net/flags/...

有關 MyBatis 內容可以訪問:http://mybatis.tk

扔个三星炸死你
<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> 
曾经蜡笔没有小新

用子查詢就不會有問題了

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

樓主可以看一下Mybatis-PageHelper count sql 轉換實作

建議樓主直接使用 Mybatis-PageHelper 實現分頁

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!