Mybatis學習系列(五)關聯查詢


前面幾節的示例基本都是一些單表查詢,實際項目中,經常用到關聯表的查詢,比如一對一,一對多等情況。在Java實體對象中,一對一和一對多可是使用包裝對象解決,屬性使用List或者Set來實現,在mybatis中一對一和一對多可是使用association或者collection標簽來配合實現。

在MyBatis中有兩種方式實現關聯查詢:

1. 嵌套結果:使用嵌套結果映射來處理重復的聯合結果的子集。首先,然讓我們來查看這個元素的屬性。所有的你都會看到,它和普通的只由 select 和resultMap 屬性的結果映射不同

2. 嵌套查詢:通過執行另外一個 SQL 映射語句來返回預期的復雜類型

一對一查詢

示例:商品表products 和 商品分類category  一個商品對應一種分類,所以products->category是一對一的關系

1.嵌套結果實現(resultMap):

通過resultMap將查詢結果中商品信息映射到Product對象中,在Product類中添加屬性category,將關聯結果映射到Product.category屬性上。

    <!-- 一對一查詢 關聯查詢 使用resultMap映射結果集 -->
    <select id="oneToOneTestMap" parameterType="int" resultMap="productInfoMap">
        select p.*,c.id
        categoryId,c.name categoryName,c.remark categoryRemark
        from products p
        join category c
        on p.categoryId= c.Id
        where p.id
        =#{value}
    </select>
    <resultMap id="productInfoMap" type="com.sl.po.Product">
        <id column="id" property="Id" />
        <result column="name" property="Name" />
        <result column="description" property="Description" />
        <result column="unitprice" property="UnitPrice" />
        <result column="imageUrl" property="ImageUrl" />
        <result column="isnew" property="IsNew" />
        <result column="citycode" property="cityCode" />
      
   <!-- association:用於映射關聯查詢單個對象的信息
      property:要將關聯查詢的分類信息映射到屬性category上
   -->
        <association property="category" javaType="com.sl.po.Category">
            <id column="categoryId" property="Id" />
            <result column="categoryName" property="Name" />
            <result column="categoryRemark" property="Remark" />
        </association>
    </resultMap>

注:也可以使用resultType配置實現,需要定義一個包裝類含有product和category兩個對象的屬性即可。

2.嵌套查詢實現

    <!-- 關聯嵌套查詢  -->
    <select id="oneToOneTestAssociationSelect" parameterType="int" resultMap="productInfoMap2">
        select p.*
        from products p
        where p.id =#{value}
    </select>
    <resultMap id="productInfoMap2" type="com.sl.po.Product" >
        <id column="id" property="Id" />
        <result column="name" property="Name" />
        <result column="description" property="Description" />
        <result column="unitprice" property="UnitPrice" />
        <result column="imageUrl" property="ImageUrl" />
        <result column="isnew" property="IsNew" />
        <result column="citycode" property="cityCode" />
        <!-- column:傳遞子查詢參數,如果要處理符復合主鍵,使用column= "{prop1=col1,prop2=col2}"  -->
        <!-- select:子查詢語句id -->
        <association property="category" javaType="com.sl.po.Category" column="categoryId" select="selectCategoryInfo">
        </association>
    </resultMap>
    <!-- 子查詢 -->
    <select id="selectCategoryInfo" parameterType="int" resultType="com.sl.po.Category">
        select * from category where id=#{id}
    </select>

使用resultType、resultMap和嵌套查詢對比分析:

resultType:使用resultType只需要將查詢結果集中的列名與定義的pojo屬性一一對應即可完成映射,缺點:resultType無法將查詢結果映射到包裝類的pojo屬性中

resultMap:需要額外定義resultMap,在resultMap中將結果集列名與pojo對象屬性一一配置。

嵌套查詢:需要定義多個查詢,上面示例定義兩個查詢,一個用於查詢products表,一個用於查詢category表。由於使用的是嵌套查詢,當操作大型數據集合和列表時將會帶來頻繁操作數據庫問題。即執行一條sql獲取結果集(oneToOneTestAssociationSelect),根據該結果集,循環執行嵌套查詢獲取具體信息(selectCategoryInfo),與上面的嵌套結果查詢相比,這種情況顯然有明顯不足。

3. 測試代碼

定義Product和Category實體,添加Mapper接口

package com.sl.po;

import java.math.BigDecimal;

public class Product {
    private int Id;
    private String Name;
    private String Description;
    private BigDecimal UnitPrice;
    private String ImageUrl;
    private Boolean IsNew;
    private String cityCode;
    private int categoryId;
    
    private Category category;
    

    public Category getCategory() {
        return category;
    }

    public void setCategory(Category category) {
        this.category = category;
    }

    public int getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(int categoryId) {
        this.categoryId = categoryId;
    }

    public String getCityCode() {
        return cityCode;
    }

    public void setCityCode(String cityCode) {
        this.cityCode = cityCode;
    }

    public int getId() {
        return Id;
    }

    public void setId(int id) {
        this.Id = id;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        this.Name = name;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        this.Description = description;
    }

    public BigDecimal getUnitPrice() {
        return UnitPrice;
    }

    public void setUnitPrice(BigDecimal unitprice) {
        this.UnitPrice = unitprice;
    }

    public String getImageUrl() {
        return Name;
    }

    public void setImageUrl(String imageurl) {
        this.ImageUrl = imageurl;
    }

    public boolean getIsNew() {
        return IsNew;
    }

    public void setIsNew(boolean isnew) {
        this.IsNew = isnew;
    }

    @Override
    public String toString() {
        return "Product [Id=" + Id + ", Name=" + Name + ", Description=" + Description + ", UnitPrice=" + UnitPrice
                + ", ImageUrl=" + ImageUrl + ", IsNew=" + IsNew + ", cityCode=" + cityCode + ", categoryId="
                + categoryId + ", category=" + category + "]";
    }

    
}
View Code
package com.sl.po;

import java.util.List;

public class Category {
    private int Id;
    private String Name;
    private String Remark;
    
    private List<Product> productList;
    
    
    public int getId() {
        return Id;
    }
    public List<Product> getProductList() {
        return productList;
    }
    public void setProductList(List<Product> productList) {
        this.productList = productList;
    }
    public void setId(int id) {
        Id = id;
    }
    public String getName() {
        return Name;
    }
    public void setName(String name) {
        Name = name;
    }

    public String getRemark() {
        return Remark;
    }
    public void setRemark(String remark) {
        Remark = remark;
    }
    
    @Override
    public String toString() {
        return "Category [Id=" + Id + ", Name=" + Name + ", Remark=" + Remark + ", productList=" + productList + "]";
    }
}
View Code
View Code
// 一對一 使用resultType映射結果集
    // @Test
    public void testSelectProduct() {

        // 獲取mapper接口的代理對象
        UnitMapper unitMapper = session.getMapper(UnitMapper.class);

        ProductDetailInfo detailInfo = unitMapper.oneToOneTest(1);

        System.out.println(detailInfo);

        // 關閉會話
        session.close();
    }

    // 一對一 使用resultMap映射結果集
    // @Test
    public void testSelectProduct2() {

        // 獲取mapper接口的代理對象
        UnitMapper unitMapper = session.getMapper(UnitMapper.class);

        Product product = unitMapper.oneToOneTestMap(2);

        System.out.println(product);

        System.out.println(product.getCategory().toString());

        // 關閉會話
        session.close();
    }

//嵌套查詢
    //一對一
    
    //@Test
    public void testSelectProductTest() {

        // 獲取mapper接口的代理對象
        UnitMapper unitMapper = session.getMapper(UnitMapper.class);

        Product product = unitMapper.oneToOneTestAssociationSelect(2);

        System.out.println(product);

        System.out.println(product.getCategory().toString());

        // 關閉會話
        session.close();
    }
View Code

一對多查詢

將上面一對一的示例倒過來看,一種類別下有多個商品,所以category->products是一對多的關系

mybatis中可以通過使用resultMap的collection標簽將關聯查詢的多條記錄映射到一個list集合屬性中。

1.嵌套結果實現

<!-- 一對多映射 -->
    <select id="oneToManyTest" resultMap="categoryInfo">
        select c.id cid,c.`name`
        cname,c.remark, p.*
        from category c
        join products p
        on p.categoryId= c.Id
        where c.id= #{cid}
    </select>
    <resultMap type="com.sl.po.Category" id="categoryInfo">
        <id column="cid" property="id" />
        <result column="cname" property="name" />
        <result column="remark" property="remark" />
        <!-- collection標簽,一對多映射,關聯當前分類下產品信息   property映射集合結果,ofType結果集類型 -->
        <collection property="productList" ofType="com.sl.po.Product">
            <id property="id" column="id" javaType="int" jdbcType="INTEGER" />
            <result column="name" property="Name" />
            <result column="description" property="Description" />
            <result column="unitprice" property="UnitPrice" />
            <result column="imageUrl" property="ImageUrl" />
            <result column="isnew" property="IsNew" />
            <result column="citycode" property="cityCode" />
        </collection>
    </resultMap>

2.嵌套查詢實現

<!-- 集合嵌套查詢 -->
    <select id="oneToManyTestCollectionSelect" resultMap="categoryInfo2">
        select *
        from category c
        where c.id= #{id}
    </select>
    <resultMap id="categoryInfo2" type="com.sl.po.Category">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="remark" property="remark" />
        <!--collection 映射一對多結果集    column:傳遞嵌套查詢參數    select:嵌套查詢id-->
        <collection property="productList" ofType="com.sl.po.Product"  column="id"  select="selectProductByCategoryId">
        </collection>
    </resultMap>
    <!-- 嵌套子查詢 -->
    <select id="selectProductByCategoryId" resultType="com.sl.po.Product">
        select *
        from products 
        where categoryId= #{id}
    </select>

測試代碼:

定義Product和Category實體同上,添加Mapper接口

public interface UnitMapper {

    Category oneToManyTest(int cId);

    Product oneToOneTestAssociationSelect(int id);
    
        //嵌套查詢中的子查詢也需要定義接口
    Category selectCategoryInfo(int id);
    
}
View Code
//一對多
@Test
    public void oneToManyTest() {

        UnitMapper unitMapper = session.getMapper(UnitMapper.class);

        Category catrgoryInfo = unitMapper.oneToManyTest(1);

        System.out.println(catrgoryInfo);

        if (catrgoryInfo.getProductList().size() > 0) {
            for (Product pro : catrgoryInfo.getProductList()) {
                System.out.println(pro);
            }
        }

        // 關閉會話
        session.close();

    }
        
//嵌套查詢 一對多
@Test
    public void testoneToManyTestCollectionSelect() {

        // 獲取mapper接口的代理對象
        UnitMapper unitMapper = session.getMapper(UnitMapper.class);

        Category category = unitMapper.oneToManyTestCollectionSelect(1);

        System.out.println(category);

        if (category.getProductList().size() > 0) {
            for (Product pro : category.getProductList()) {
                System.out.println(pro);
            }
        }
        // 關閉會話
        session.close();
    }
View Code

多對多查詢

示例:一個訂單包含多個商品,一個商品也可以對應多個訂單,這個示例查詢稍微擴展一下,增加用戶信息,一個用戶對應多個訂單

實體對象定義:定義User實體,增加orders屬性,用於映射當前用戶的訂單; 定義Order對象,增加orderItems屬性,映射當前訂單有哪些內容(產品);定義OrderItem實體,增加product屬性,映射具體產品信息

<!-- 多對多映射 查詢用戶信息及對應訂單信息,訂單詳情 -->
    <!-- select * from orders o join `user` u on o.userId = u.id join orderItem 
        i on o.Id = i.orderid join products p on i.productid = p.Id -->
    <select id="manyToManyTest" resultMap="userAndOrderInfo">
        select u.*,
        o.id oid,
        o.createtime ocreatetime,
        o.userid ouserid,
        o.amount oamount,
        o.remark
        oremark,
        i.id iid,
        i.orderid iorderid,
        i.productid iproductid,
        i.createtime icreatetime,
        i.number inumber,
        i.price iprice,

        p.id pid,
        p.`name` pname,
        p.Description pdescription

        from orders o
        join `user` u on
        o.userId = u.id
        join orderItem i on o.Id = i.orderid
        join products p on
        i.productid = p.Id
        where u.id=#{id}
    </select>
    <resultMap type="com.sl.po.User" id="userAndOrderInfo">
        <id column="id" property="id" />
        <result column="sex" property="sex" />
        <result column="birthday" property="birthday" />
        <result column="address" property="address" />
        <result column="username" property="userName" />
        <!-- 映射用戶對應的訂單信息,一個用戶可以有多個訂單 -->
        <collection property="orders" ofType="com.sl.po.Order">
            <id column="oid" property="id" />
            <result column="ocreatetime" property="createTime" />
            <result column="ouserid" property="userId" />
            <result column="oamount" property="amount" />
            <result column="oremark" property="remark" />
            <!-- 訂單對應的商品信息,一個訂單可以有多個商品  -->
            <collection property="orderItems" ofType="com.sl.po.OrderItem">
                <id column="iid" property="id" />
                <result column="iorderid" property="orderId" />
                <result column="iproductid" property="productId" />
                <result column="icreatetime" property="createTime" />
                <result column="inumber" property="number" />
                <result column="iprice" property="price" />
                <!-- 映射商品信息 (OrderItem與商品product 一一對應)-->
                <association property="product" javaType="com.sl.po.Product">
                    <id column="pid" property="Id" />
                    <result column="pname" property="Name" />
                    <result column="pdescription" property="Description" />
                </association>
            </collection>
        </collection>
    </resultMap>

測試代碼

package com.sl.po;

import java.sql.Date;
import java.util.List;

public class User {
    
    private int id;
    private String sex;
    private Date birthday;
    private String address;
    private String userName;
    
    //映射當前用戶訂單列表
    private List<Order> orders;
    
    
    public List<Order> getOrders() {
        return orders;
    }
    public void setOrders(List<Order> orders) {
        this.orders = orders;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    
    @Override
    public String toString() {
        return "User [id=" + id + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + ", userName="
                + userName + ", orders=" + orders + "]";
    }
    
    
    
}
View Code
package com.sl.po;

import java.sql.Date;
import java.util.List;

public class Order {
    
    private int id;
    private int userId;
    private Date createTime;
    private int amount;
    private String remark;
    
    private User user;
    //映射訂單內容(產品信息)
    private List<OrderItem> orderItems;
    
    
    
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public int getAmount() {
        return amount;
    }
    public void setAmount(int amount) {
        this.amount = amount;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public List<OrderItem> getOrderItems() {
        return orderItems;
    }
    public void setOrderItems(List<OrderItem> orderItems) {
        this.orderItems = orderItems;
    }
    
}
View Code
package com.sl.po;

public class OrderItem {
    
    private int id;
    private int orderId;
    private int productId;
    private int createTime;
    private int number;
    private int price;

    //訂單項對應的具體產品
    private Product product;
    
    
    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getOrderId() {
        return orderId;
    }

    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }

    public int getProductId() {
        return productId;
    }

    public void setProductId(int productId) {
        this.productId = productId;
    }

    public int getCreateTime() {
        return createTime;
    }

    public void setCreateTime(int createTime) {
        this.createTime = createTime;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

}
View Code
package com.sl.mapper;

import java.util.List;

import com.sl.po.Category;
import com.sl.po.Product;
import com.sl.po.ProductDetailInfo;
import com.sl.po.User;

public interface UnitMapper {

    User manyToManyTest(int id);
}
View Code
//多對多
    @Test
    public void manyToManyTest() {

        UnitMapper unitMapper = session.getMapper(UnitMapper.class);

        User userOrder = unitMapper.manyToManyTest(1);

        System.out.println(userOrder);
        
        // 關閉會話
        session.close();

    }
View Code

標簽即屬性說明

Association標簽: 作用是可以將關聯查詢信息映射到一個pojo對象中

collection標簽: 作用是可以將關聯查詢信息映射到一個集合中

Association和collection標簽常用到的屬性:

Property屬性: 指定當前association標簽內容映射到pojo對象中哪個屬性。

javaType:映射屬性的類型

typeHandler:類型處理器,使用這個屬性,你可以覆蓋默認的 typeHandler 類型處理器。 這個屬性值是類的完全限定名或者是一個類型處理器的實現, 或者是類型別名

column:sql結果集列名,用在嵌套查詢時傳遞參數,要 處 理 復 合 主 鍵 , 你 可 以 指 定 多 個 列 名 通 過 column= ” {prop1=col1,prop2=col2} ” 這種語法來傳遞給嵌套查詢語 句。prop1 和 prop2 以參數對象形式來設置給目標嵌套查詢語句。

select:嵌套查詢映射語句的ID

fetchType:可選的。有效值為 lazy和eager。 如果使用了,它將取代全局配置參數lazyLoadingEnabled

columnPrefix:將含有指定前綴的結果集映射到當前標簽下 例如:<association property="productInfo" columnPrefix="p_" /> 將結果集中以“p_”開頭的列映射到productInfo屬性上

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM