元素中,包含了一個子元素,MyBatis就是通過該元素來處理一對一關(guān)聯(lián)關(guān)系的。" /> 亚洲欧美乱色另类小说,精品国产天天在线2019

MyBatis怎樣處理一對一關(guān)聯(lián)關(guān)系?

更新時間:2021-06-24 來源:黑馬程序員 瀏覽量:

在現(xiàn)實生活中,一對一關(guān)聯(lián)關(guān)系是十分常見的。例如,一個人只能有一個身份證,同時一個身份證也只會對應(yīng)一個人,它們之間的關(guān)系模型圖,如圖1所示。

MyBatis怎樣處理一對一關(guān)聯(lián)關(guān)系

圖1 人與身份證的關(guān)聯(lián)關(guān)系

那么使用MyBatis是怎么處理圖1中的這種一對一關(guān)聯(lián)關(guān)系的呢?在<resultMap>元素中,包含了一個<association>子元素,MyBatis就是通過該元素來處理一對一關(guān)聯(lián)關(guān)系的。

在<association>元素中,通??梢耘渲靡韵聦傩裕?/p>

● property:指定映射到的實體類對象屬性,與表字段一一對應(yīng);

● column:指定表中對應(yīng)的字段;

● javaType:指定映射到實體對象屬性的類型;

● select:指定引入嵌套查詢的子SQL語句,該屬性用于關(guān)聯(lián)映射中的嵌套查詢;

● fetchType:指定在關(guān)聯(lián)查詢時是否啟用延遲加載。fetchType屬性有l(wèi)azy和eager兩個屬性值,默認(rèn)值為lazy(即默認(rèn)關(guān)聯(lián)映射延遲加載)。

<association>元素的使用非常簡單,只需要參考如下兩種示例配置即可,具體如下:

<!--方式一:嵌套查詢-->
<association property="card" column="card_id" 
javaType="com.itheima.po.IdCard"
             select="com.itheima.mapper.IdCardMapper.findCodeById" />
<!--方式二:嵌套結(jié)果-->
<association property="card" javaType="com.itheima.po.IdCard">
    <id property="id" column="card_id" />
    <result property="code" column="code" />
</association>

注意:

MyBatis在映射文件中加載關(guān)聯(lián)關(guān)系對象主要通過兩種方式:嵌套查詢和嵌套結(jié)果。嵌套查詢是指通過執(zhí)行另外一條SQL映射語句來返回預(yù)期的復(fù)雜類型;嵌套結(jié)果是使用嵌套結(jié)果映射來處理重復(fù)的聯(lián)合結(jié)果的子集。開發(fā)人員可以使用上述任意一種方式實現(xiàn)對關(guān)聯(lián)關(guān)系的加載。

了解了MyBatis中處理一對一關(guān)聯(lián)關(guān)系的元素和方式后,接下來就以個人和身份證之間的一對一關(guān)聯(lián)關(guān)系為例,進行詳細(xì)講解。

查詢個人及其關(guān)聯(lián)的身份證信息是先通過查詢個人表中的主鍵來獲個人信息,然后通過表中的外鍵,來獲取證件表中的身份證號信息。其具體實現(xiàn)步驟如下:

(1)創(chuàng)建數(shù)據(jù)表。在mybatis數(shù)據(jù)庫中分別創(chuàng)建名為tb_idcard和tb_person的數(shù)據(jù)表,同時預(yù)先插入兩條數(shù)據(jù)。其執(zhí)行的SQL語句如下所示:

USE mybatis;
# 創(chuàng)建一個名稱為tb_idcard的表
CREATE TABLE  tb_idcard( 
     id INT PRIMARY KEY AUTO_INCREMENT,
     CODE VARCHAR(18)
);
# 插入2條數(shù)據(jù)
INSERT INTO tb_idcard(CODE) VALUES('152221198711020624');
INSERT INTO tb_idcard(CODE) VALUES('152201199008150317');
# 創(chuàng)建一個名稱為tb_person的表
CREATE TABLE  tb_person( 
     id INT PRIMARY KEY AUTO_INCREMENT,
     name VARCHAR(32),
     age INT,
     sex VARCHAR(8),
     card_id INT UNIQUE,     
     FOREIGN KEY(card_id) REFERENCES tb_idcard(id)
);
# 插入2條數(shù)據(jù)
INSERT INTO tb_person(name,age,sex,card_id) VALUES('Rose',29,'女',1);
INSERT INTO tb_person(name,age,sex,card_id) VALUES('tom',27,'男',2);

完成上述操作后,數(shù)據(jù)庫tb_idcard和tb_person表中的數(shù)據(jù)如圖2所示。

MyBatis怎樣處理一對一關(guān)聯(lián)關(guān)系

圖2 tb_idcard和tb_person表

(2)在Eclipse中創(chuàng)建一個名為chapter09的Web項目,然后引入相關(guān)JAR包、log4j日志文件、MybatisUtils工具類以及mybatis-config.xml核心配置文件。項目環(huán)境搭建完成后的文件結(jié)構(gòu),如圖3所示。

1624527322485_43.png

圖3 項目文件結(jié)構(gòu)

(3)在項目的com.itheima.po包下創(chuàng)建持久化類IdCard和Person,編輯后的代碼,如文件1和文件2所示。

文件1 IdCard.java

     package com.itheima.po;
     /**
      * 證件持久化類
      */
     public class IdCard {
         private Integer id;
         private String code;
         public Integer getId() {
             return id;
         }
         public void setId(Integer id) {
             this.id = id;
         }
         public String getCode() {
             return code;
         }
         public void setCode(String code) {
             this.code = code;
         }
         @Override
         public String toString() {
             return "IdCard [id=" + id + ", code=" + code + "]";
         }
     }


文件2 Person.java

     package com.itheima.po;
     /**
      * 個人持久化類
      */
     public class Person {
         private Integer id;
         private String name;
         private Integer age;
         private String sex;
         private IdCard card;  //個人關(guān)聯(lián)的證件
         public Integer getId() {
             return id;
         }
         public void setId(Integer id) {
             this.id = id;
         }
         public String getName() {
             return name;
         }
         public void setName(String name) {
             this.name = name;
         }
         public Integer getAge() {
             return age;
         }
         public void setAge(Integer age) {
             this.age = age;
         }
         public String getSex() {
             return sex;
         }
         public void setSex(String sex) {
             this.sex = sex;
         }
         public IdCard getCard() {
             return card;
         }
         public void setCard(IdCard card) {
             this.card = card;
         }
         @Override
         public String toString() {
             return "Person [id=" + id + ", name=" + name + ", "
                     + "age=" + age + ", sex=" + sex + ", card=" + card + "]";
         }
     }

在上述兩個文件中,分別定義了各自的屬性以及對應(yīng)的getter/setter方法,同時為了方便查看輸出結(jié)果還重寫了toString()方法。

(4)在com.itheima.mapper包中,創(chuàng)建證件映射文件IdCardMapper.xml和個人映射文件PersonMapper.xml,并在兩個映射文件中編寫一對一關(guān)聯(lián)映射查詢的配置信息,如文件3和文件4所示。

文件3 IdCardMapper.xml

    <?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.itheima.mapper.IdCardMapper">
       <!-- 根據(jù)id查詢證件信息 -->
       <select id="findCodeById" parameterType="Integer" resultType="IdCard">
           SELECT * from tb_idcard where id=#{id}
       </select>
     </mapper>


文件4 PersonMapper.xml

     <?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.itheima.mapper.PersonMapper">
         <!-- 嵌套查詢:通過執(zhí)行另外一條SQL映射語句來返回預(yù)期的特殊類型 -->
         <select id="findPersonById" parameterType="Integer" 
                                           resultMap="IdCardWithPersonResult">
             SELECT * from tb_person where id=#{id}
         </select>
         <resultMap type="Person" id="IdCardWithPersonResult">
             <id property="id" column="id" />
             <result property="name" column="name" />
             <result property="age" column="age" />
             <result property="sex" column="sex" />
             <!-- 一對一:association使用select屬性引入另外一條SQL語句 -->
             <association property="card" column="card_id" javaType="IdCard"
                 select="com.itheima.mapper.IdCardMapper.findCodeById" />
         </resultMap>
     </mapper>

在上述兩個映射文件中,使用了MyBatis中的嵌套查詢方式進行了個人及其關(guān)聯(lián)的證件信息查詢,因為返回的個人對象中除了基本屬性外還有一個關(guān)聯(lián)的card屬性,所以需要手動編寫結(jié)果映射。從映射文件PersonMapper.xml中可以看出,嵌套查詢的方法是先執(zhí)行一個簡單的SQL語句,然后在進行結(jié)果映射時,將關(guān)聯(lián)對象在<association>元素中使用select屬性執(zhí)行另一條SQL語句(即IdCardMapper.xml中的SQL)。

(5)在核心配置文件mybatis-config.xml中,引入Mapper映射文件并定義別名,如文件5所示。

文件5 mybatis-config.xml

     <?xml version="1.0" encoding="UTF-8" ?>
     <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
     <configuration>
         <!-- 引入數(shù)據(jù)庫連接配置文件 -->
         <properties resource="db.properties" />
         <!--使用掃描包的形式定義別名 -->
         <typeAliases>
             <package name="com.itheima.po" />
         </typeAliases>
         <!--配置環(huán)境 ,默認(rèn)的環(huán)境id為mysql -->
         <environments default="mysql">
             <!-- 配置id為mysql的數(shù)據(jù)庫環(huán)境 -->
             <environment id="mysql">
                 <!-- 使用JDBC的事務(wù)管理 -->
                 <transactionManager type="JDBC" />
                 <!--數(shù)據(jù)庫連接池 -->
                 <dataSource type="POOLED">
                     <property name="driver" value="${jdbc.driver}" />
                     <property name="url" value="${jdbc.url}" />
                     <property name="username" value="${jdbc.username}" />
                     <property name="password" value="${jdbc.password}" />
                 </dataSource>
             </environment>
         </environments>
         <!--配置Mapper的位置 -->
          <mappers>
              <mapper resource="com/itheima/mapper/IdCardMapper.xml" />
              <mapper resource="com/itheima/mapper/PersonMapper.xml" />
          </mappers>
     </configuration>

在上述核心配置文件中,首先引入了數(shù)據(jù)庫連接的配置文件,然后使用掃描包的形式自定義別名,接下來進行環(huán)境的配置,最后配置了Mapper映射文件的位置信息。

(6)在com.itheima.test包中,創(chuàng)建測試類MybatisAssociatedTest,并在類中編寫測試方法findPersonByIdTest(),如文件6所示。

文件6 MybatisAssociatedTest.java

     package com.itheima.test;
     import org.apache.ibatis.session.SqlSession;
     import org.junit.Test;
     import com.itheima.po.Person;
     import com.itheima.utils.MybatisUtils;
     /**
      * Mybatis關(guān)聯(lián)查詢映射測試類
      */
     public class MybatisAssociatedTest {
         /**
          * 嵌套查詢
          */
         @Test
         public void findPersonByIdTest() {
             // 1、通過工具類生成SqlSession對象
             SqlSession session = MybatisUtils.getSession();
             // 2.使用MyBatis嵌套查詢的方式查詢id為1的人的信息
             Person person = session.selectOne("com.itheima.mapper." 
                                        + "PersonMapper.findPersonById", 1);
             // 3、輸出查詢結(jié)果信息
             System.out.println(person);
             // 4、關(guān)閉SqlSession
             session.close();
         }
     }

在文件6的findPersonByIdTest()方法中,首先通過MybatisUtils工具類獲取了SqlSession對象,然后通過SqlSession對象的selectOne()方法獲取了個人信息。為了查看結(jié)果,這里使用了輸出語句輸出查詢結(jié)果信息。最后程序執(zhí)行完畢時,關(guān)閉了SqlSession。

使用JUnit4執(zhí)行findPersonByIdTest()方法后,控制臺的輸出結(jié)果如圖4所示。

MyBatis怎樣處理一對一關(guān)聯(lián)關(guān)系

圖4 運行結(jié)果

從圖4可以看出,使用MyBatis嵌套查詢的方式查詢出了個人及其關(guān)聯(lián)的身份證信息,這就是MyBatis中的一對一關(guān)聯(lián)查詢。

雖然使用嵌套查詢的方式比較簡單,但是從圖4中可以看出,MyBatis嵌套查詢的方式要執(zhí)行多條SQL語句,這對于大型數(shù)據(jù)集合和列表展示不是很好,因為這樣可能會導(dǎo)致成百上千條關(guān)聯(lián)的SQL語句被執(zhí)行,從而極大的消耗數(shù)據(jù)庫性能并且會降低查詢效率。這并不是開發(fā)人員所期望的。為此,我們可以使用MyBatis提供的嵌套結(jié)果方式,來進行關(guān)聯(lián)查詢。

在PersonMapper.xml中,使用MyBatis嵌套結(jié)果的方式進行個人及其關(guān)聯(lián)的證件信息查詢,所添加的代碼如下所示:

<!-- 嵌套結(jié)果:使用嵌套結(jié)果映射來處理重復(fù)的聯(lián)合結(jié)果的子集 -->
<select id="findPersonById2" parameterType="Integer" 
                                   resultMap="IdCardWithPersonResult2">
    SELECT p.*,idcard.code
    from tb_person p,tb_idcard idcard
    where p.card_id=idcard.id 
    and p.id= #{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult2">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <result property="age" column="age" />
    <result property="sex" column="sex" />
    <association property="card" javaType="IdCard">
        <id property="id" column="card_id" />
        <result property="code" column="code" />
    </association>
</resultMap>

從上述代碼中可以看出,MyBatis嵌套結(jié)果的方式只編寫了一條復(fù)雜的多表關(guān)聯(lián)的SQL語句,并且在<association>元素中繼續(xù)使用相關(guān)子元素進行數(shù)據(jù)庫表字段和實體類屬性的一一映射。

在測試類MybatisAssociatedTest中,編寫測試方法findPersonByIdTest2(),其代碼如下所示。

/**
 * 嵌套結(jié)果
 */
@Test
public void findPersonByIdTest2() {
    // 1、通過工具類生成SqlSession對象
    SqlSession session = MybatisUtils.getSession();
    // 2.使用MyBatis嵌套結(jié)果的方法查詢id為1的人的信息
    Person person = session.selectOne("com.itheima.mapper." 
                               + "PersonMapper.findPersonById2", 1);
    // 3、輸出查詢結(jié)果信息
    System.out.println(person);
    // 4、關(guān)閉SqlSession
    session.close();
}

使用JUnit4執(zhí)行findPersonByIdTest2()方法后,控制臺的輸出結(jié)果如圖5所示。

MyBatis怎樣處理一對一關(guān)聯(lián)關(guān)系

圖5 運行結(jié)果

從圖5可以看出,使用MyBatis嵌套結(jié)果的方式只執(zhí)行了一條SQL語句,并且同樣查詢出了個人及其關(guān)聯(lián)的身份證的信息。

MyBatis延遲加載的配置:

在使用MyBatis嵌套查詢方式進行MyBatis關(guān)聯(lián)查詢映射時,使用MyBatis的延遲加載在一定程度上可以降低運行消耗并提高查詢效率。MyBatis默認(rèn)沒有開啟延遲加載,需要在核心配置文件mybatis-config.xml中的<settings>元素內(nèi)進行配置,具體配置方式如下:

<settings>
     <!-- 打開延遲加載的開關(guān) -->  
    <setting name="lazyLoadingEnabled" value="true" />  
    <!-- 將積極加載改為消息加載,即按需加載 -->  
    <setting name="aggressiveLazyLoading" value="false"/>  
</settings>

在映射文件中,MyBatis關(guān)聯(lián)映射的<association>元素和<collection>元素中都已默認(rèn)配置了延遲加載屬性,即默認(rèn)屬性fetchType="lazy"(屬性fetchType="eager"表示立即加載),所以在配置文件中開啟延遲加載后,無需在映射文件中再做配置。






猜你喜歡:

MyBatis框架操作數(shù)據(jù)庫有哪些步驟?

Java類加載機制詳解【java面試題】

MyBatis框架如何實現(xiàn)數(shù)據(jù)查詢?有幾種方法?

黑馬程序員Java高級軟件工程師培訓(xùn)課程

分享到:
和我們在線交談!