MyBatis - 4 - 【奧義】映射文件(自增主鍵獲取)、 參數名映射(源碼)、${}和#{}(jdbcType)、map映射、resultMap、discriminator

在這裏插入圖片描述

在這裏插入圖片描述

# 入門:簡單 靜態 SQL 映射

在這裏插入圖片描述

在這裏插入圖片描述

## 獲取 新增數據id? (MySQL 、 Oracle)

原生 使用 statement 的方法
在這裏插入圖片描述

mysql 支持自增主鍵,自增主鍵值的獲取,mybatis 也是利用 statement.getGeneratedKey()

  • useGeneratedKeys="true" 使用自增組件獲取主鍵值策略
  • keyProperty 指定對應的主鍵屬性,也就是 mybatis 獲取到主鍵值以後,封裝到 javaBean 的哪個屬性
  • keyColumn 指定 數據庫查出的表中,哪一列是 id
    在這裏插入圖片描述

Oracle 怎麼搞?
在這裏插入圖片描述

## @Param

  • POJO:
    如果多個參數正好是我們業務邏輯的數據模型,我們就可以直接傳入 pojo
    #{屬性名}:取出傳入的 pojo 的屬性值

  • Map:
    如果多個參數不是業務模型中的數據,沒有對應的 pojo ,爲了方便傳入 map
    #{key}:取出key 對應的 value

  • TO:
    如果多個參數不是業務模型中的數據,但是經常要使用,推薦來編寫一個 TO(Transfer Object) 數據傳輸對象

    class Page{
    	int index;
    	int size;
    }
    

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述


# 進階1(@Param 和 參數名映射 源碼分析)

以 selectById 爲例,step into
在這裏插入圖片描述
來到 MapperProxy 的 invoke 方法
在這裏插入圖片描述

MapperProxy 實現了 InvocationHandler 接口
在這裏插入圖片描述

當前要執行的方法 ⇒ 參數 method
在這裏插入圖片描述

繼續看 invoke 方法 (下面圖)
第一行 Object.class.equals(method.getDeclaringClass())
判斷如果是 Object 的方法(如 toString 方法)

直接放行

在這裏插入圖片描述
否則,進行處理(下圖)

首先,final MapperMethod mapperMethod = cachedMapperMethod(method);
把 method 包裝成 MapperMethod
(這塊不是重點,暫時跳過)
在這裏插入圖片描述
看上圖 第二句代碼 mapperMethod.execute(sqlSession, args);

作用:執行mapper方法

先看傳入的參數

args 的 1 是我們傳入的 參數 id
在這裏插入圖片描述

sqlsession

在這裏插入圖片描述

下面 step into execute方法

在這裏插入圖片描述
從 command 裏面獲取數據
知道是 增刪查改的 哪個方法(這裏是 select)
在這裏插入圖片描述

首先會執行執行 method.convertArgsToSqlCommandParam(args) (看下圖)
把 args 傳入的 參數 轉換爲 param sql語句
在這裏插入圖片描述

select 方法有點特殊(下圖)

會先判斷返回類型

返回 void?多個?Map?圖標(Cursor)?或者一個對象(else)
在這裏插入圖片描述

可以看到(下圖)

查詢一個的情況,底層調用的 還是 sqlSession 的 selectOne 方法 ()

只不過 這裏需要傳入的是 處理好的 param
在這裏插入圖片描述

所以 , step into method.convertArgsToSqlCommandParam(args); 看看是怎麼玩的

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述
可以看到(上圖)
names 已經有值了
值怎麼來的?

ParamNameResolver 構造時候 賦值的(下圖)

在這裏插入圖片描述

在這裏插入圖片描述

(上圖)最後,map 把 name 值 put 進去
然後 上面 有 isUseActualParamName 方法,值 根據 配置 確定的

如果配置了爲 true 並且是 jdk1.8 之後的。
那麼,就使用方法簽名中的名稱作爲語句參數名稱
在這裏插入圖片描述
在這裏插入圖片描述

好,知道 names 的值是怎麼來的了,
現在 ,回到 getNamedParams 方法 (下圖)
第一層 if 判斷 args 的數目

如果 數目爲0 ⇒ return null
如果 數目爲1 ⇒ 返回第一個
否則 遍歷取值
在這裏插入圖片描述
如:names={0=id,1=lastName}param={id:args[0] , lastName:args[1]}

前者用於 匹配參數名,後者用於 根據參數名 找 參數值

在這裏插入圖片描述

# 入門 :#{} 和 ${} 的區別

  • #{}:是以預編譯的形式,將參數設置到 sql 語句中,PreparedStatement 防止 sql 注入
  • ${}:取出的值直接拼裝在 sql 語句中;會有安全問題

    但也有使用情況:
    如 列名的拼接
    select * from ${year}_salary where xxx;
    select * from tbl_employee order by ${f_name} ${order} ;

在這裏插入圖片描述
#{}:更豐富的用法
規定參數的一些規則:

在這裏插入圖片描述

## JdbcType.class

jdbcType 通常需要在某種特定條件下被設置:
在我們數據爲 null 的時候, 有些數據庫(如Oracle)可能不能識別 mybatis 對 null 的默認處理

如 Oracle 在這種情況下就會報錯
原因:JdbcType OTHER , 無效的類型,因爲 mybatis 對所有的 null 映射都是 原生 Jdbc 的 OTHER 類型。而 Oracle 無法識別 OTHER 類型

在這裏插入圖片描述

在 JdbcType.class 裏面可以看到所有的 類型
在這裏插入圖片描述

對於 上面 Oracle 不支持 OTHER 類型,
解決方法有兩個如下:

  1. (在 #{…} 裏面 加 jdbcType=NULL

  2. 全局配置(jdbcTypeForNull)
    在這裏插入圖片描述

# 入門:map映射

第一種 map 映射(【一條數據】key:屬性名、value:屬性值)
在這裏插入圖片描述

在這裏插入圖片描述

第二種 map 映射(【多條數據】key:對象 id、value:對象)

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

# 入門:select 標籤 中的屬性

在這裏插入圖片描述

# 入門 :resultMap

在這裏插入圖片描述
resultMap resultType 只能 二選一

在這裏插入圖片描述

在這裏插入圖片描述

# 入門:resultMap - 級聯 - 一對多

在這裏插入圖片描述

# 入門:association 聯合 查詢

在這裏插入圖片描述

# 入門:association 分步查詢(爲延時加載做鋪墊)

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

# 入門:延時加載(按需加載)

上面的 分步查詢有一個問題
:我們每次查詢 Employee 對象的時候,將把 Dept 一起查詢出來。
我們希望,部門信息在我們使用的時候再去查詢。
.
實現起來其實很簡單。
只需要在 分段查詢的基礎上 加上兩個配置

  • lazyLoadingEnabled 懶加載 。 設置所有的懶加載
  • aggressiveLazyLoading 如果開啓,懶加載也會完全的加載全部屬性。否則,只有需要時候才加載

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

# 入門:collection 聯合查詢

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

# 入門:collection 分步查詢

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

## 傳多列時候怎麼搞?

在這裏插入圖片描述

## fetchType

在這裏插入圖片描述

# 入門:discriminator 鑑別器

鑑別器:mybatis 可以使用 discriminator 判斷某列的值,然後根據某列的值改變封裝行爲
封裝 Employee:
如果查出的是女生,就把部門信息查詢出來,否則不查詢
如果是男生,把 last_name 這一列的值賦值給 email
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章