1. 程式人生 > >學會MyBatis中的級聯

學會MyBatis中的級聯

一、概述

MyBatis中的級聯分為三種

  • 鑑別器(discriminator): 根據一些條件決定實現類級聯的方案。比如體檢表需要根據性別區分。
  • 一對一(association): 比如學生與學生證就是一對一的關係。
  • 一對多(collection): 比如班級與學生就是一對多的關係。

MyBatis中沒有多對多的級聯,一般使用兩個一對多的級聯代替。

二、瞭解resultMap元素的作用

resultMap定義的主要是一個結果集的對映關係,也就是SQL到Java Bean的對映關係定義,它也支援級聯等特性。現版本的MyBatis只支援resusltMap查詢,不支援更新或則儲存。

resultMap元素的子元素

<resultMap>
   <constructor>
       <idArg/>
       <arg/>
   </constructor>
   <id />
   <result />
   <association />
   <collection />
   <discriminator>
       <case/>
   </discriminator>
</resultMap>
  • constructor:用於在例項化類時,注入結果到構造方法中

  • idArg:ID 引數;標記出作為 ID 的結果可以幫助提高整體效能

  • arg:將被注入到構造方法的一個普通結果

  • id:一個 ID 結果;標記出作為 ID 的結果可以幫助提高整體效能

  • result:注入到欄位或 JavaBean 屬性的普通結果

  • association:一個複雜型別的關聯。許多結果將包裝成這種型別巢狀結果對映,關聯可以指定為一個 resultMap 元素,或者引用一個

  • collection:一個複雜型別的集合。巢狀結果對映,集合可以指定為一個 resultMap 元素,或者引用一個

  • discriminator:使用結果值來決定使用哪個 resultMap

  • case:基於某些值的結果對映。巢狀結果對映一個 case 也是一個對映它本身的結果,因此可以包含很多相 同的元素,或者它可以參照一個外部的 resultMap。

三、案例

這裡我們提供建立一個案例,建立了兩個表customer表和invoice表,其中customer表和invoice表的關係是一對多。建立實體類時我們把invoice表中關於billing的資訊提取出來建立一個BillingInfo實體類,其他的欄位建立成一個實體類。這兩個實體類之間的關係是一對一。注意閱讀註釋會有詳細的解釋

資料庫

DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer` (
  `customer_id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(8) DEFAULT NULL,
  `last_name` varchar(8) DEFAULT NULL,
  `company` varchar(32) DEFAULT NULL,
  `address` varchar(64) DEFAULT NULL,
  `city` varchar(8) DEFAULT NULL,
  `state` varchar(8) DEFAULT NULL,
  `country` varchar(8) DEFAULT NULL,
  `postal_code` char(6) DEFAULT NULL,
  `phone` char(11) DEFAULT NULL,
  `fax` varchar(16) DEFAULT NULL,
  `email` varchar(16) DEFAULT NULL,
  `support_repld` varchar(4) DEFAULT NULL,
  PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `invoice`;
CREATE TABLE `invoice` (
  `invoice_id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_id` int(11) DEFAULT NULL,
  `invoice_date` datetime DEFAULT NULL,
  `billing_address` varchar(32) DEFAULT NULL,
  `billing_city` varchar(16) DEFAULT NULL,
  `billing_state` varchar(4) DEFAULT NULL,
  `billing_country` varchar(16) DEFAULT NULL,
  `billing_postalcode` varchar(8) DEFAULT NULL,
  `total` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`invoice_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

實體類

public class CustomerEntity {
    int customerId;
    String firstName;
    String lastName;
    String company;
    String address;
    String city;
    String state;
    String country;
    String postalCode;
    String phone;
    String fax;
    String email;
    String supportRepld;
	// 客戶customer和發票invoice是一對多關係
    List<InvoiceEntity> invoiceEntityList= null;

	// ..省略get\set方法
}

public class BillingInfoEntity {
    int invoiceId;
    String billingAddress;
    String billingCity;
    String billingState;
    String billingCountry;
    String billingPostalCode;
	// ..省略get\set方法
}

public class InvoiceEntity {
    int invoiceId;
    Date invoiceDate;
    float total;
	
	// 發票invoice和賬單billing是一對一關係
    BillingInfoEntity billingInfoEntity;
	
	// 發票invoice和客戶customer是一對一關係 
    CustomerEntity customerEntity;

	// ..省略get\set方法
}

查詢

這裡我們對於resultMap使用級聯採用了兩種方式Nested ResultMapNested Select

介面

public interface SelectMapper {
	
	// Nested ResultMap方式定義的方法
	
    InvoiceEntity getInvoiceByInvoiceId(int id);

    InvoiceEntity getInvoiceForCustomerByInvoiceId(int id);

    CustomerEntity getCustomerById(int id);

	// Nested Select方式定義的方法
    CustomerEntity getCusById(int id);

    List<InvoiceEntity> getIncByCustomerId(int id);

    List<CustomerEntity> getAll();
}

對映器

<?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.lzx.select.mappers.SelectMapper">

    <!-- Nested ResultSet(多用於多表連線查詢,只需查詢一次即可,但是語句複雜)-->
	
	<!--
		根據實體類InvoiceEntity中描述的關係建立一個新的結果集,association適用於一對一的關係。
		在這裡,invoice裡面的欄位mybatis會自動幫我們對映,前提是你的資料庫命名和欄位的命名要符合規範
	-->
	<!--
		type屬性為resultMap的對映的實體類,可以使用完全限定名,也可以使用別名
		autoMapping為是否啟動自動對映,預設值是false,不啟動
	 -->
    <resultMap id="invoiceAndBilling" type="InvoiceEntity" autoMapping="true">
		<!--association用於一對一級聯,property是pojo中的屬性。javaType是java這邊的型別。 -->
        <association property="billingInfoEntity" javaType="BillingInfoEntity" autoMapping="true"/>
		<!--resultMap之間的相互引用-->
        <association property="customerEntity" resultMap="customerInfo"/>
    </resultMap>
    
	<!-- 
		根據實體類CustomerEntity中描述的關係建立一個新的結果集,collection適用於一對多的關係。
	-->
    <resultMap id="customerInfo" type="CustomerEntity" autoMapping="true">
    	<!--這裡的ofType等同於association中的javaType-->    
		<collection property="invoiceEntityList" 
			resultMap="invoiceAndBilling" ofType="InvoiceEntity" />
    </resultMap>
	
    <select id="getInvoiceByInvoiceId" resultMap="invoiceAndBilling">
        select * from invoice where invoice_id = #{id}
    </select>

    <select id="getInvoiceForCustomerByInvoiceId" resultMap="invoiceAndBilling">
        select
        i.invoice_id,
        i.invoice_date,
        i.billing_address,
        i.billing_city,
        i.billing_state,
        i.billing_country,
        i.billing_postalCode,
        i.total,
        c.*
        from invoice i
        left join customer c
        on c.customer_id = i.invoice_id
        where i.invoice_id = #{id}
    </select>

    <select id="getCustomerById" resultMap="customerInfo">
      select *
      from invoice i
      left join customer c
      on c.customer_id = i.invoice_id
      where c.customer_id = #{id}
    </select>


    <!--Nested Select (也可用於多表連線查詢,但是要查詢多次,效率低,但是SQL語句簡單)-->
    <resultMap id="invoiceAndCustomer" type="InvoiceEntity" autoMapping="true">
        <association property="billingInfoEntity" javaType="BillingInfoEntity" autoMapping="true"/>
		<!--select屬性級聯到customer的查詢方法,column屬性代表傳入的引數-->
        <association property="customerEntity" column="customer_id"
                     select="com.lzx.select.mappers.SelectMapper.getCusById"/>
    </resultMap>

    <resultMap id="customerAndInvoice" type="CustomerEntity" autoMapping="true">
        <collection property="invoiceEntityList" column="customer_id"
                    select="com.lzx.select.mappers.SelectMapper.getIncByCustomerId"/>
    </resultMap>



    <select id="getIncByCustomerId" resultMap="invoiceAndCustomer" >
        select * from invoice where customer_id = #{id}
    </select>

    <select id="getCusById" resultMap="customerAndInvoice">
        select * from customer where customer_id = #{id}
    </select>

    <select id="getAll" resultType="com.lzx.select.entity.CustomerEntity">
        select * from customer
    </select>	    
</mapper>