1. 程式人生 > >15、Mybatis之一對多級聯查詢

15、Mybatis之一對多級聯查詢

<1>通過一個表的一個欄位去查詢另一個表的多條記錄

一對多的級聯查詢表示一個表中一條記錄對應另一個表中多條記錄,例如一種型號的手機有多個人使用。
手機對應的表為PHONE:
這裡寫圖片描述
人對應的表PERSON:
這裡寫圖片描述

建立PHONE表對應的實體類,一個品牌的手機有多個人在使用

package com.lzj.mybaits.bean;
public class Phone {    
    private String brand;
    private float price;
    private List<Person> persons;
    /*省略get和set方法*/
}

建立PERSON表對應的實體類:

package com.lzj.mybaits.bean;
public class Person {   
    private int id;
    private String name;
}

下面介紹兩種一對多的級聯查詢方式:集合封裝查詢和分佈查詢。

方式一:集合封裝查詢

通過phone_brand欄位查詢出所有使用指定型號品牌的人
1、建立Dao介面

package com.lzj.mybatis.dao;
import com.lzj.mybaits.bean.Phone;
public interface PhoneDao
{
public Phone getPhone(String brand); }

2、建立sql的mapper檔案

<mapper namespace="com.lzj.mybatis.dao.PhoneDao">

    <!--巢狀結果集的方式,使用collection標籤定義關聯的集合型別的屬性封裝規則 -->
    <resultMap type="com.lzj.mybaits.bean.Phone" id="MyPhone">
        <id column="brand" property="brand"/>
<result column="price" property="price"/> <!-- collection定義關聯集合型別的屬性的封裝規則 ofType:指定集合裡面元素的型別 --> <collection property="persons" ofType="com.lzj.mybaits.bean.Person"> <id column="id" property="id"/> <result column="name" property="name"/> </collection> </resultMap> <select id="getPhone" resultMap="MyPhone"> SELECT ph.phone_brand brand, ph.phone_price price, ps.id, ps.name FROM PHONE ph LEFT JOIN PERSON ps ON ph.phone_brand=ps.phone_brand WHERE ph.phone_brand=#{brand} </select> </mapper>

3、建立查詢方法

    public static void testGepPhone(){
        String resource = "conf.xml";
        InputStream in = MybaitsTest.class.getClassLoader().getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);   
        SqlSession session = factory.openSession();
        PhoneDao phoneDao = session.getMapper(PhoneDao.class);
        Phone phone = phoneDao.getPhone("iphone");
        System.out.println("phone :" + phone);
    }

執行測試方法,輸出結果如下:

phone :Phone [brand=iphone, price=5000.0, persons=[Person [id=1, name=lzj], Person [id=4, name=Bob]]]

方式二:分佈查詢

PHONE表與PERSON表時一對多的關係,PHONE表中一條資料對應PERSON表中的多條資料。因此也可以先查PHONE表,然後用查到的記錄再去查PERSON表,實現分佈查詢。
先查PHONE表,首先建立PHONE表對應的DAO介面:

package com.lzj.mybatis.dao;
import com.lzj.mybaits.bean.Phone;
public interface PhoneDao {
    public Phone getPhoneByStep(String brand);
}

建立PHONE表對應的mapper檔案

<mapper namespace="com.lzj.mybatis.dao.PhoneDao">

    <resultMap type="com.lzj.mybaits.bean.Phone" id="MyPhoneStep">
        <id column="phone_brand" property="brand"/>
        <result column="phone_price" property="price"/>
        /*用collection 定義一條PHONE資料對應多條PERSON資料;
        返回型別為Phone,property="persons"指明phone中persons屬性對應多條資料;
        select指定呼叫介面中的方法,返回多條資料放在persons屬性中*/
        <collection property="persons" select="com.lzj.mybatis.dao.PersonDao.getPersonByPhone"
            column="phone_brand">
        </collection>
    </resultMap>

    /*查詢PHONE表*/
    <select id="getPhoneByStep" resultMap="MyPhoneStep">
        select * from PHONE where phone_brand=#{brand}
    </select>

</mapper>

由於上面呼叫了PERSON對應介面中查詢方法,下面定義PERSON對應的DAO:

package com.lzj.mybatis.dao;
import com.lzj.mybaits.bean.Person;
public interface PersonDao {
    /*上面PHONE表對應的mapper檔案用slelect指明瞭要呼叫該方法*/
    public Person getPersonByPhone(String brand);
}

PERSON表對應的mapper檔案為:

<mapper namespace="com.lzj.mybatis.dao.PersonDao">
    <select id="getPersonByPhone" resultType="com.lzj.mybaits.bean.Person">
        select * from PERSON where phone_brand=#{brand}
    </select>
</mapper>

建立測試方法:

    public static void testGepPhoneByStep(){
        String resource = "conf.xml";
        InputStream in = MybaitsTest.class.getClassLoader().getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);   
        SqlSession session = factory.openSession();
        PhoneDao phoneDao = session.getMapper(PhoneDao.class);
        Phone phone = phoneDao.getPhoneByStep("iphone");
        System.out.println("phone :" + phone);
    }

執行測試方法,輸出結果:

phone :Phone [brand=iphone, price=5000.0, persons=[Person [id=1, name=lzj], Person [id=4, name=Bob]]]

<2>通過一個表的多個欄位去查詢另一個表的多條記錄

上面的示例都是查詢PHONE表後,然後用查詢的phone_brand欄位資料去查詢PERSON表的記錄。如果查詢PHONE表後,需要用多個欄位去查詢PERSON表呢?此時就需要在collection標籤中的column指定具體對應的列名,如下形式:

column="{key1=column1,key2=column2}"

查詢一個表後,用查詢到的記錄中的一個欄位對應的資料去查其它表也可以用這種形式,本例中通過phone_brand欄位去查PERSON表可改成如下形式:
只需要把PHONE的mapper檔案中的<resultMap > 中的內容改成如下形式(只改了column中內容)

    <resultMap type="com.lzj.mybaits.bean.Phone" id="MyPhoneStep">
        <id column="phone_brand" property="brand"/>
        <result column="phone_price" property="price"/>
        /*column="{brand=phone_brand}"指定把phone_brand列傳給brand鍵*/
        <collection property="persons" select="com.lzj.mybatis.dao.PersonDao.getPersonByPhone"
            column="{brand=phone_brand}">
        </collection>
    </resultMap>

注意:column="{brand=phone_brand}" 中的brand鍵不是隨意些的,要與select=”com.lzj.mybatis.dao.PersonDao.getPersonByPhone”中獲取的鍵值名相同。

    /*#{brand}與column="{brand=phone_brand}中的鍵值保持一致*/
    <select id="getPersonByPhone" resultType="com.lzj.mybaits.bean.Person">
        select * from PERSON where phone_brand=#{brand}
    </select>

假設要通過查詢PHONE表的phone_brand和name再去查PERSON時,PHONE表對應的mapper檔案中的<resultMap > 中的<collection> 標籤中的column可以寫成如下形式:

column="{brand=phone_brand,userName=name}"

在PERSON的select語句中獲取兩個鍵對應的值就可以了

    <select id="getPersonByPhone" resultType="com.lzj.mybaits.bean.Person">
        select * from PERSON where phone_brand=#{brand} AND name=#{username}
    </select>