• <nav id="dstbx"></nav>

    <nav id="dstbx"></nav>
    1. <form id="dstbx"></form>
    2. <small id="dstbx"></small>

      教育行業A股IPO第一股(股票代碼 003032)

      全國咨詢/投訴熱線:400-618-4000

      MyBatis怎樣處理一對一關聯關系?分步驟介紹

      更新時間:2021年06月24日18時01分 來源:傳智教育 瀏覽次數:

      在現實生活中,一對一關聯關系是十分常見的。例如,一個人只能有一個身份證,同時一個身份證也只會對應一個人,它們之間的關系模型圖,如圖1所示。

      MyBatis怎樣處理一對一關聯關系

      圖1 人與身份證的關聯關系

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

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

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

      ● column:指定表中對應的字段;

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

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

      ● fetchType:指定在關聯查詢時是否啟用延遲加載。fetchType屬性有lazy和eager兩個屬性值,默認值為lazy(即默認關聯映射延遲加載)。

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

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

      注意:

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

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

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

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

      USE mybatis;
      # 創建一個名稱為tb_idcard的表
      CREATE TABLE  tb_idcard( 
           id INT PRIMARY KEY AUTO_INCREMENT,
           CODE VARCHAR(18)
      );
      # 插入2條數據
      INSERT INTO tb_idcard(CODE) VALUES('152221198711020624');
      INSERT INTO tb_idcard(CODE) VALUES('152201199008150317');
      # 創建一個名稱為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條數據
      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);

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

      MyBatis怎樣處理一對一關聯關系

      圖2 tb_idcard和tb_person表

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

      1624527322485_43.png

      圖3 項目文件結構

      (3)在項目的com.itheima.po包下創建持久化類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;  //個人關聯的證件
               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 + "]";
               }
           }

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

      (4)在com.itheima.mapper包中,創建證件映射文件IdCardMapper.xml和個人映射文件PersonMapper.xml,并在兩個映射文件中編寫一對一關聯映射查詢的配置信息,如文件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">
             <!-- 根據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">
               <!-- 嵌套查詢:通過執行另外一條SQL映射語句來返回預期的特殊類型 -->
               <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中的嵌套查詢方式進行了個人及其關聯的證件信息查詢,因為返回的個人對象中除了基本屬性外還有一個關聯的card屬性,所以需要手動編寫結果映射。從映射文件PersonMapper.xml中可以看出,嵌套查詢的方法是先執行一個簡單的SQL語句,然后在進行結果映射時,將關聯對象在<association>元素中使用select屬性執行另一條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>
               <!-- 引入數據庫連接配置文件 -->
               <properties resource="db.properties" />
               <!--使用掃描包的形式定義別名 -->
               <typeAliases>
                   <package name="com.itheima.po" />
               </typeAliases>
               <!--配置環境 ,默認的環境id為mysql -->
               <environments default="mysql">
                   <!-- 配置id為mysql的數據庫環境 -->
                   <environment id="mysql">
                       <!-- 使用JDBC的事務管理 -->
                       <transactionManager type="JDBC" />
                       <!--數據庫連接池 -->
                       <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>

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

      (6)在com.itheima.test包中,創建測試類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關聯查詢映射測試類
            */
           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、輸出查詢結果信息
                   System.out.println(person);
                   // 4、關閉SqlSession
                   session.close();
               }
           }

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

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

      MyBatis怎樣處理一對一關聯關系

      圖4 運行結果

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

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

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

      <!-- 嵌套結果:使用嵌套結果映射來處理重復的聯合結果的子集 -->
      <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嵌套結果的方式只編寫了一條復雜的多表關聯的SQL語句,并且在<association>元素中繼續使用相關子元素進行數據庫表字段和實體類屬性的一一映射。

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

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

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

      MyBatis怎樣處理一對一關聯關系

      圖5 運行結果

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

      MyBatis延遲加載的配置:

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

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

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







      猜你喜歡:

      Mybatis原理介紹:MyBatis如何操作數據庫?

      什么是Mybatis?Mybaits有哪些優點?

      Mybatis執行SQL命令是怎么實現的?

      MyBatis中使用#和$有什么區別?

      傳智教育java開發培訓

      0 分享到:
      神马影院我不卡