Mybatis 自動映射


什么是自動映射?

介紹自動映射之前先看一下手動映射,如下:

<resultMap id="orderModelMap1" type="com.javacode2018.chat05.demo7.model.OrderModel">
    <id column="id" property="id"/>
    <result column="userId" property="userId" />
    <result column="createTime" property="createTime" />
    <result column="upTime" property="upTime" />
</resultMap>

<select id="getById1" resultMap="orderModelMap1">
    <![CDATA[
    SELECT
        a.id,
        a.user_id userId,
        a.create_time createTime,
        a.up_time upTime
    FROM
        t_order a
    WHERE
        a.id = #{value}
    ]]>
</select>

注意上面的 resultMap 元素中有 4 行配置,如下:

<id column="id" property="id"/>
<result column="userId" property="userId" />
<result column="createTime" property="createTime" />
<result column="upTime" property="upTime" />

這4行代碼用於配置 sql 結果的列和 OrderModel 對象中字段的映射關系。

大家有沒有注意到,映射規則中 column 和 property 元素的值都是一樣.

mybatis 中支持自動映射配置,當開啟自動映射之后,當 sql 的列名和 Model 中的字段名稱是一樣的時候(不區分大小寫),mybatis 內部會進行自動映射,不需要我們手動去寫上面的 4 行映射規則。

下面我們將上面的示例改成自動映射的方式,如下:

<resultMap id="orderModelMap2" type="com.javacode2018.chat05.demo7.model.OrderModel" autoMapping="true">
</resultMap>

<select id="getById2" resultMap="orderModelMap2">
    <![CDATA[
    SELECT
        a.id,
        a.user_id userId,
        a.create_time createTime,
        a.up_time upTime
    FROM
        t_order a
    WHERE
        a.id = #{value}
    ]]>
</select>

注意上面的 resultMap 中的autoMapping屬性,是否開啟自動映射,我們設置為 true,這樣 mybatis 會自動按照列名和 Model 中同名的字段進行映射賦值。

上面兩個配置最后查詢結果是一樣的,都會將查詢結果對應的 4 個字段的值自動賦值給 OrderModel 中同名的屬性。

自動映射開關

mybatis 中自動映射主要有 2 種配置,一種是全局的配置,對應用中所有的 resultMap 起效,這個是在 mybatis 配置文件中進行設置的;另外一種是通過resultMap 的 autoMapping 屬性進行配置。

mybatis 判斷某個 resultMap 是否開啟自動映射配置的時候,會先查找自身的 autoMapping 屬性,如果這個屬性設置值了,就直接用這個屬性的值,如果resultMap 元素的 autoMapping 屬性沒有配置,則走全局配置的自動映射規則。

下面我們來詳解介紹一下這款的內容。

mybatis 自動映射全局配置

在 mybatis 全局配置文件中加入下面配置:

<settings>
    <setting name="autoMappingBehavior" value="自動映射規則"/>
</settings>

autoMappingBehavior 值來源於枚舉:org.apache.ibatis.session.AutoMappingBehavior,源碼:

public enum AutoMappingBehavior {

  /**
   * Disables auto-mapping.
   */
  NONE,

  /**
   * Will only auto-map results with no nested result mappings defined inside.
   */
  PARTIAL,

  /**
   * Will auto-map result mappings of any complexity (containing nested or otherwise).
   */
  FULL
}
  • NONE:關閉全局映射開關

  • PARTIAL:對除在內部定義了嵌套結果映射(也就是連接的屬性)以外的屬性進行映射,這個也是默認值。

  • FULL:自動映射所有屬性。

下面我們來演示一下autoMappingBehavior每種配置的效果。

NONE

mybatis-config.xml 加入配置

<settings>
    <!-- 關閉自動映射開關 -->
    <setting name="autoMappingBehavior" value="NONE"/>
</settings>

OrderMapper.xml

<resultMap id="orderModelMap4" type="com.javacode2018.chat05.demo7.model.OrderModel">
</resultMap>

<select id="getById4" resultMap="orderModelMap4">
    <![CDATA[
    SELECT
        a.id,
        a.user_id userId,
        a.create_time createTime,
        a.up_time upTime
    FROM
        t_order a
    WHERE
        a.id = #{value}
    ]]>
</select>

OrderMapper.java加入

OrderModel getById4(int id);

測試用例

com.javacode2018.chat05.demo7.Demo7Test#getById4

@Test
public void getById4() throws IOException {
    this.before("demo7/mybatis-config1.xml");
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById4(2);
        log.info("{}", orderModel);
    }
}

運行結果

21:58.821 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime FROM t_order a WHERE a.id = ? 
21:58.850 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - ==> Parameters: 2(Integer)
21:58.868 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - <==      Total: 1
21:58.868 [main] INFO  c.j.chat05.demo7.Demo7Test - null

從輸出中可以看到最后一樣輸出結果為 null,sql 實際上返回的是有結果的,但是結果映射的時候返回的是空。

結果解釋

由於 mybatis 全局配置中將 autoMappingBehavior 的值置為了 NONE,表示全局自動映射被關閉了,而 resultMapper 中的 orderModelMap4 沒有配置autoMapping 屬性,所以最終這個查詢結果不會自動映射,所以最后查詢結果為 null。

PARTIAL

對除在內部定義了嵌套結果映射(也就是連接的屬性)以外的屬性進行映射,這個也是 autoMappingBehavior 的默認值。

mybatis-config.xml加入配置

<settings>
    <!-- 對除在內部定義了嵌套結果映射(也就是連接的屬性)以外的屬性進行映射,這個也是autoMappingBehavior的默認值。 -->
    <setting name="autoMappingBehavior" value="PARTIAL"/>
</settings>

OrderMapper.xml

<resultMap id="orderModelMap5" type="com.javacode2018.chat05.demo7.model.OrderModel">
</resultMap>

<select id="getById5" resultMap="orderModelMap5">
    <![CDATA[
    SELECT
        a.id,
        a.user_id userId,
        a.create_time createTime,
        a.up_time upTime
    FROM
        t_order a
    WHERE
        a.id = #{value}
    ]]>
</select>

OrderMapper.java加入

OrderModel getById5(int id);

測試用例

com.javacode2018.chat05.demo7.Demo7Test#getById5

@Test
public void getById5() throws IOException {
    this.before("demo7/mybatis-config2.xml");
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById5(2);
        log.info("{}", orderModel);
    }
}

運行結果

28:32.612 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById5 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime FROM t_order a WHERE a.id = ? 
28:32.648 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById5 - ==> Parameters: 2(Integer)
28:32.664 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById5 - <==      Total: 1
28:32.665 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1577947790, upTime=1577947790, userModel=null)

OrderModel 中的 4 個屬性被自動映射成功了。

結果解釋

orderModelMap5 中沒有指定 autoMapping 屬性,所以自動映射會走全局配置的規則,即 PARTIAL,會進行自動映射。

我們再來看看 PARTIAL 的解釋:對除在內部定義了嵌套結果映射(也就是連接的屬性)以外的屬性進行映射。這句話是什么意思?

有些復雜的查詢映射會在 resultMap 中嵌套一些映射(如:association,collection),當使用 PARTIAL 的時候,如果有嵌套映射,則這個嵌套映射不會進行自動映射了。

通過訂單id查詢出訂單以及訂單用戶的信息,sqlmap如下:

<resultMap id="orderModelMap6" type="com.javacode2018.chat05.demo7.model.OrderModel">
    <association property="userModel">
    </association>
</resultMap>

<select id="getById6" resultMap="orderModelMap6">
    <![CDATA[
    SELECT
        a.id,
        a.user_id userId,
        a.create_time createTime,
        a.up_time upTime
        b.id as user_id,
        b.name
    FROM
        t_order a,t_user b
    WHERE
        a.user_id = b.id
        AND a.id = #{value}
    ]]>
</select>

OrderModel.java

package com.javacode2018.chat05.demo7.model;

import lombok.*;

import java.util.List;

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderModel {
    private Integer id;
    private Integer userId;
    private Long createTime;
    private Long upTime;
    private UserModel userModel;
}

內部有個 userModel 屬性引用用戶對象。

UserModel.java
package com.javacode2018.chat05.demo7.model;

import lombok.*;

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserModel {
    private Integer id;
    private String name;
}

OrderMapper.java中加入

OrderModel getById6(int id);

測試用例

com.javacode2018.chat05.demo7.Demo7Test#getById6
@Test
public void getById6() throws IOException {
    this.before("demo7/mybatis-config2.xml");
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById6(2);
        log.info("{}", orderModel);
    }
}

運行輸出

52:49.037 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = ? 
52:49.066 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==> Parameters: 2(Integer)
52:49.087 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - <==      Total: 1
52:49.088 [main] INFO  c.j.chat05.demo7.Demo7Test - null

sql 查詢實際上是有一條記錄的,但是最后返回的是 null,說明沒有進行自動映射。

FULL

自動映射所有屬性。

這次Mapper我們不動,還是下面這樣,沒有手動指定映射規則。

<resultMap id="orderModelMap6" type="com.javacode2018.chat05.demo7.model.OrderModel">
    <association property="userModel">
    </association>
</resultMap>

<select id="getById6" resultMap="orderModelMap6">
    <![CDATA[
    SELECT
        a.id,
        a.user_id userId,
        a.create_time createTime,
        a.up_time upTime
        b.id as user_id,
        b.name
    FROM
        t_order a,t_user b
    WHERE
        a.user_id = b.id
        AND a.id = #{value}
    ]]>
</select>

修改一下 autoMappingBehavior 的值為 FULL,看看效果。

mybatis配置

<settings>
    <!-- 自動映射所有屬性 -->
    <setting name="autoMappingBehavior" value="FULL"/>
</settings>

測試用例

com.javacode2018.chat05.demo7.Demo7Test#getById6_0

@Test
public void getById6_0() throws IOException {
    this.before("demo7/mybatis-config3.xml");
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById6(2);
        log.info("{}", orderModel);
    }
}

運行輸出

56:05.127 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = ? 
56:05.155 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==> Parameters: 2(Integer)
56:05.186 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - <==      Total: 1
56:05.186 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1577947790, upTime=1577947790, userModel=UserModel(id=2, name=張學友))

輸出中可以看到 OrderModel 所有屬性都是有值的,userModel 的 2 個屬性也有值,userModel.id 是 2,我們運行一下 sql 看看,用戶 id 是多少,如下:

mysql> SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = 2;
+----+--------+------------+------------+---------+-----------+
| id | userId | createTime | upTime     | user_id | name      |
+----+--------+------------+------------+---------+-----------+
|  2 |      1 | 1577947790 | 1577947790 |       1 | 張學友    |
+----+--------+------------+------------+---------+-----------+
1 row in set (0.00 sec)

user_id 實際上是 1,mybatis 中按照 sql 字段和 model 結果字段同名進行自動映射,所以將訂單的 id 賦值給 userModel 的 id 屬性了。

此時需要我們 orderModelMap6 的配置,手動指定一下 user_id 和 userModel.id 的映射規則,如下:

<resultMap id="orderModelMap6" type="com.javacode2018.chat05.demo7.model.OrderModel">
    <association property="userModel">
        <id column="user_id" property="id"/>
    </association>
</resultMap>

再次運行測試用例

com.javacode2018.chat05.demo7.Demo7Test#getById6_0

輸出

15:02.751 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = ? 
15:02.783 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==> Parameters: 2(Integer)
15:02.801 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - <==      Total: 1
15:02.801 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1577947790, upTime=1577947790, userModel=UserModel(id=1, name=張學友))

這次 userModel 中的 id 正確了。

總結

  1. 所謂自動映射,就是 mybatis 會自動按照列名和 Model 中同名的字段(column=property)進行映射賦值,不用手動編寫映射規則。

  2. 在 resultMap 中指定了 autoMapping 屬性值為 true 時,就會開啟自動映射。

  3. 設置全局自動映射,需要在 mybatis 全局配置文件中設置 autoMappingBehavior

  4. 寫 mapper.xml 的時候,建議將映射的配置都給寫上去,這樣能夠杜絕一些隱患,使我們的系統更穩定。

參考資源

1.https://cloud.tencent.com/developer/article/1581433

每天學習一點點,每天進步一點點。


免責聲明!

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



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