1. 程式人生 > >mybatis精講(三)--標籤及TypeHandler使用

mybatis精講(三)--標籤及TypeHandler使用

目錄

  • 話引
  • XML配置標籤
    • 概覽
  • properties
    • 子標籤property
    • resource
    • 程式注入
  • settings
  • 別名
  • TypeHandler
    • 自定義TypeHandler
    • EnumTypeHandler
    • EnumOrdinalTypeHandler
    • SexTypeHandler
    • typeHandler注意點
  • # 加入戰隊
    • 微信公眾號

話引

  • 前兩張我們分別介紹了Mybatis環境搭建及其元件的生命週期。這些都是我們Mybatis入門必備技能。有了前兩篇的鋪墊我們今天就來深入下Mybatis, 也為了填下之前埋下的坑。

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=""/>
    <!--設定-->
    <settings/>
    <!--定義別名-->
    <typeAliases>
        <package name=""/>
    </typeAliases>
    <!--型別處理器-->
    <typeHandlers/>
    <!--物件工廠-->
    <objectFactory/>
    <!--外掛-->
    <plugins/>
    <!--定義資料庫資訊,預設使用development資料庫構建環境-->
    <environments default="development">
        <environment id="development">
            <!--jdbc事物管理-->
            <transactionManager type="JDBC"/>
            <!--配置資料庫連線資訊-->
            <dataSource type="POOLED"/>
        </environment>
    </environments>
    <!--資料庫廠商標識-->
    <databaseIdProvider/>
    <mappers/>
</configuration>

  • 上面模板列出了所有xml可以配置的屬性。這裡plugins是一個讓人哭笑不得的東西。用的好是利器,用的不好就是埋坑。接下來我們來看看各個屬性的作用

properties

  • 該標籤的作用就是引入變數。和maven的properties一樣。在這裡定義的變數或者引入的變數,在下面我們是可以童工${}使用的。

子標籤property


<properties>
  <property name="zxhtom" value="jdbc:mysql://localhost:3306/mybatis"/>
</properties>

<dataSource type="POOLED">
<property name="driver" value="${zxhtom}"/>
<dataSource>
  • 上述的配置就可以直接使用zxhtom這個變數。

resource

  • 除了上述方法我們還可以通過引入其他properties檔案,就可以使用檔案裡的配置變量了。

<properties resource="mybatis.properties"/>

程式注入

  • 最後還有一種我們在構建SqlSessionFactory的時候重新載入我們的Properties物件就可以了。另外三者的優先順序是從低到高

settings


configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
  • 上面程式碼是我們在XMLConfigBuilder解析settings標籤的程式碼。從這段程式碼中我們瞭解到settings子標籤。
引數 功能 可選值 預設值
autoMappingBehavior 指定Mybatis應如何自動對映列到欄位上。
NONE : 表示取消自動對映
PARTIAL:只會自動對映沒有定義巢狀結果集對映的結果集
FULL : 自動對映任意複雜的結果集
NONE、PARTIAL、FULL PARTIAL
autoMappingUnknownColumnBehavior 指定識別到位置列或屬性的時間
NONE : 什麼都不做
WARNING:日誌會報警(前提是日誌設定了顯示許可權)
FAILING : 丟擲異常。
NONE, WARNING, FAILING NONE
cacheEnabled 該配置影響的所有對映器中配置的快取的全域性開關 true|false true
proxyFactory 指定Mybatis建立具有延遲載入能力的物件所用到的代理工具未指定時將自動查詢 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING not set
lazyLoadingEnabled 延時載入全域性開關
開啟時:級聯物件會延時載入;級聯標籤中可以通過fetchType來定製覆蓋此選項
true|false false
aggressiveLazyLoading 啟用時:對任意延遲屬性的呼叫會使帶有延遲載入屬性的物件分層性質完整載入,反之按需載入 true|false true
multipleResultSetsEnabled 是否允許單一語句返回多結果集 true|false true
useColumnLabel 確切的說當對映找不到引數時會使用列標籤(資料庫列名)代替別名去對映 true|false true
useGeneratedKeys 允許 JDBC 支援自動生成主鍵,需要驅動相容。 如果設定為 true 則這個設定強制使用自動生成主鍵,儘管一些驅動不能相容但仍可正常工作(比如 Derby) true|false false
defaultExecutorType 配置預設的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(prepared statements); BATCH 執行器將重用語句並執行批量更新 SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 設定超時時間,決定驅動等待資料庫響應的秒數 整數 null
defaultFetchSize 設定資料庫resultSet讀取資料方式,預設全部載入進記憶體,設定該屬性可以設定一次性讀多少條資料進記憶體 整數 null
mapUnderscoreToCamelCase 是否開啟自動駝峰命名規則(camel case)對映,即從經典資料庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的類似對映。 true|false false
safeRowBoundsEnabled -允許在巢狀語句中使用分頁 true|false false
localCacheScope 一級快取。mybatis預設對同一個sqlsession中資料是共享的。一個sqlsession呼叫兩次相同查詢實際只會查詢一次。就是因為該屬性為SESSION , STATEMENT則針對的是每一條sql SESSION|STATEMENT SESSION
jdbcTypeForNull 當沒有為引數提供特定的jdbc型別時,為空值則指定JDBC型別。在新增時我們沒有設定引數,這個時候就會根據此引數天長。加入設定VARCHAR,那麼我們新增的資料沒傳引數則為空字元 NULL|VARCHAR|OTHER OTHER
lazyLoadTriggerMethods 指定具體方法延時載入 方法 equals,clone,hashCode,toString
safeResultHandlerEnabled 允許在巢狀語句中使用分頁 true|false true
defaultScriptingLanguage 動態SQL生成的預設語言 org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
defaultEnumTypeHandler mybatis預設的列舉處理類
callSettersOnNulls 指定當結果集中值為null的時候是否呼叫對映物件的setter(put)方法。
useActualParamName 允許使用他們的編譯後名稱來對映,3.4.2後預設true.在xml中#{0}則報錯。設定為false,則#{0}代表第一個引數#{n}第n個 true|false true
returnInstanceForEmptyRow 當返回行的所有列都是空時,MyBatis預設返回 null。 當開啟這個設定時,MyBatis會返回一個空例項。 請注意,它也適用於巢狀的結果集 (如集合或關聯)。(新增於 3.4.2) true|false false
logPrefix 指定 MyBatis 增加到日誌名稱的字首。

別名

  • 別名是mybatis為我們專案中類起的一個名字,類名往往會很長所以別名就方便我們平時的開發。Mybatis為我們內建了一些類的別名:byte、short、int、long、float、double、boolean、char等基礎型別的別名。還有其的封裝型別、String,Object,Map,List等等常用的類。
    org.apache.ibatis.type.TypeAliasRegistry這個類中幫我們內建了別名。可以看下。自定義別名也是通過這個類進行註冊的。我們可以通過settings中typeAliases配置的方式結合@Alias。或者掃描包也可以的。

TypeHandler

  • 這個介面就四個方法

public interface TypeHandler<T> {

  /**
   * 設定引數是用到的方法
   */
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  T getResult(ResultSet rs, String columnName) throws SQLException;

  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}
  • 可以理解成攔截器。它主要攔截的是設定引數和獲取結果的兩個節點。這個類的作用就是將Java物件和jdbcType進行相互轉換的一個功能。同樣的在org.apache.ibatis.type.TypeHandlerRegistry這個類中mybatis為我們提供了內建的TypeHandler。基本上是對於基本資料和分裝物件的轉換。
  • 下面我們隨便看一個TypeHandler處理細節
public class BooleanTypeHandler extends BaseTypeHandler<Boolean> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setBoolean(i, parameter);
  }

  @Override
  public Boolean getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    boolean result = rs.getBoolean(columnName);
    return !result && rs.wasNull() ? null : result;
  }

  @Override
  public Boolean getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {
    boolean result = rs.getBoolean(columnIndex);
    return !result && rs.wasNull() ? null : result;
  }

  @Override
  public Boolean getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {
    boolean result = cs.getBoolean(columnIndex);
    return !result && cs.wasNull() ? null : result;
  }
}
  • setParameter是PreparedStatement進行設定成boolean型別。getResult分別通過三種不同方式獲取。在這些方法裡我們可以根據自己也無需求進行控制。常見的控制是列舉的轉換。傳遞引數過程可能是列舉的name,但是傳遞到資料庫中要列舉的index.這種需求我們就可以在TypeHandler中實現。我們書寫的typeHandler之後並不能被識別,還需要我們在resultMap中的result標籤中通過typeHandler指定我們的自定義Handler.

自定義TypeHandler

  • 承接上文我們說道列舉的轉換。下面我們還是已學生類為例。學生中性別之前是boolean型別。現在我們採用列舉型別。但是資料庫中存的還是資料,01.

EnumTypeHandler

  • 在TypeHandlerRegister類中申明瞭預設的列舉類處理器是private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  String s = rs.getString(columnName);
  return s == null ? null : Enum.valueOf(type, s);
}
  • 我們通過這個方法可以看出,這個列舉處理器適合已列舉名稱儲存的方式


EnumOrdinalTypeHandler

  • 在Enum中還有一個屬性oridinal。這個表示列舉中的索引。然後我們通過檢視Mybatis提供的處理器發現有個叫EnumOrdinalTypeHandler。我們很容易聯想到的就是這個處理器是通過列舉的所以作為資料庫內容的。在SexEnum中MALE儲存到資料庫中則為0.注意這個0不是我們的index.而是MALE的索引。如果將MALE和FEMAEL調換。那麼MALE索引則為1.

  • 因為預設的是EnumTypeHandler。所以想用EnumOrdinalTypeHandler的話我們要麼在resultMap中sex欄位指定該處理器。要不就通過配置檔案typeHandlers註冊進來。(將處理器與Java類進行繫結。mybatis遇到這個Java物件的時候就知道用什麼處理器處理)


<typeHandlers>
    <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.github.zxhtom.enums.SexEnum"/>
</typeHandlers>

SexTypeHandler

  • 上面的不管是通過名稱儲存還是通過索引儲存都不太滿足我們的需求。我們想通過我們的index儲存。那麼這時候我們就得自定義處理邏輯了。Mybatis處理器都是繼承BaseTypeHandler。因為BaseTypeHandler實現了TypeHandler.所以我們這裡也就繼承BaseTypeHandler。

public class SexTypeHandler extends BaseTypeHandler<SexEnum> {


    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i,parameter.getIndex());
    }

    @Override
    public SexEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int i = rs.getInt(columnName);
        return SexEnum.getSexEnum(i);
    }

    @Override
    public SexEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int i = rs.getInt(columnIndex);
        return SexEnum.getSexEnum(i);
    }

    @Override
    public SexEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int i = cs.getInt(columnIndex);
        return SexEnum.getSexEnum(i);
    }
}

typeHandler注意點

  • 在編寫自定義處理器的時候我們得之處Javatype、jdbctype。兩者不是必填。但至少得有一個。正常我們預設javatype是必填的。
  • 填寫的方式有三種
    • 通過MappedTypes、MappedJdbcTypes分別指定javatype、jdbctype
    • 通過在mybatis-config.xml中配置typeHandlers進行註解。裡面也有這兩個屬性的配置。
    • 通過在mapper.xml的resultmap中再次指定某個欄位的typehandler.
  • TypeHandler為我們提供了Java到jdbc資料的轉換橋樑。極大的方便了我們平時的開發。讓我們開發期間忽略資料的轉換這麼糟心的事情。

加入戰隊

# 加入戰隊

微信公眾號

相關推薦

mybatis()--標籤TypeHandler使用

目錄 話引 XML配置標籤 概覽 properties 子標籤property resource 程式注入

Mybatis(一)---環境配置架構梳理

目錄 簡介 ORM模型 Hibernate Ibatis 環境搭建 jar 配置 xml方式配置 程式碼方式配

Vue 基礎()

Class 與 Style 繫結 繫結 HTML Class 繫結內聯樣式 繫結 HTML Class 物件語法 對div中的 class 進行繫結後, activated 這個 class 存在與否將取決於資

Mybatis(二)---生命週期

目錄 回顧 SqlSessionFactoryBuilder SqlSessionFactory openSessionFromDataSource Executor

mybatis(四)--ObjectFactory

目錄 前言 mybatis的ObjectFactory 原始碼 setProperties  create instantiateClass

mybatis(五)--對映器元件

目錄 前言 標籤 select insert|update|delete 引數 resultMap cache 自定義快取

mybatis(六)--二級快取

目錄 簡介 配置 原始碼 CachingExecutor 缺點 自定義二級快取 簡介 上一章節我們簡單瞭解了二級快取的配置。今

十八節,Python分布式爬蟲打造搜索引擎Scrapy—深度優先與廣度優先原理

.com nbsp 網站 color -1 廣度 spa .cn png 第三百三十八節,Python分布式爬蟲打造搜索引擎Scrapy精講—深度優先與廣度優先原理 網站樹形結構 深度優先 是從左到右深度進行爬取的,以深度為準則從左到右的執行 第三百三十

百五十三節,Python分布式爬蟲打造搜索引擎Scrapy—scrapy的暫停與重啟

ctrl+ 裏的 dir 其中 重啟 requests 引擎 image .cn 第三百五十三節,Python分布式爬蟲打造搜索引擎Scrapy精講—scrapy的暫停與重啟 scrapy的每一個爬蟲,暫停時可以記錄暫停狀態以及爬取了哪些url,重啟時可以從暫停狀態開始

百五十四節,Python分布式爬蟲打造搜索引擎Scrapy—數據收集(Stats Collection)

ack 高效 所有 crawl resp spider 方法 啟動 定義 第三百五十四節,Python分布式爬蟲打造搜索引擎Scrapy精講—數據收集(Stats Collection) Scrapy提供了方便的收集數據的機制。數據以key/value方式存儲,值大多是

百五十五節,Python分布式爬蟲打造搜索引擎Scrapy—scrapy信號詳解

第一個 如果 -c stopped lin 支持 idle 資源 spider 第三百五十五節,Python分布式爬蟲打造搜索引擎Scrapy精講—scrapy信號詳解 信號一般使用信號分發器dispatcher.connect(),來設置信號,和信號觸發函數,當捕獲到信號

百五十八節,Python分布式爬蟲打造搜索引擎Scrapy—將bloomfilter(布隆過濾器)集成到scrapy-redis中

分布式爬蟲 times 操作 加載 ger 目錄 需要 ini space 第三百五十八節,Python分布式爬蟲打造搜索引擎Scrapy精講—將bloomfilter(布隆過濾器)集成到scrapy-redis中,判斷URL是否重復 布隆過濾器(Bloom Filte

百六十一節,Python分布式爬蟲打造搜索引擎Scrapy—倒排索引

索引原理 文章 根據 file 索引 -i span 需要 style 第三百六十一節,Python分布式爬蟲打造搜索引擎Scrapy精講—倒排索引 倒排索引 倒排索引源於實際應用中需要根據屬性的值來查找記錄。這種索引表中的每一項都包括一個屬性值和具有該屬性值的各記錄的

百六十五節,Python分布式爬蟲打造搜索引擎Scrapy—elasticsearch(搜索引擎)的查詢

搜索引擎 ack 復合 分布式 內置 分布 在一起 一起 分類 第三百六十五節,Python分布式爬蟲打造搜索引擎Scrapy精講—elasticsearch(搜索引擎)的查詢 elasticsearch(搜索引擎)的查詢 elasticsearch是功能非常強大的搜索

百六十八節,Python分布式爬蟲打造搜索引擎Scrapy—elasticsearch(搜索引擎)用Django實現搜索的自動補全功能

技術 django 分布 全功能 -s col ron 搜索 創建 第三百六十八節,Python分布式爬蟲打造搜索引擎Scrapy精講—用Django實現搜索的自動補全功能 elasticsearch(搜索引擎)提供了自動補全接口 官方說明:https://www

BGP(一)——原理內外部鄰居配置

BGPBGP概述 一、BGP/BGP4:Border Gateway Protocol,邊界網關協議 是一種基於距離矢量算法的自治系統之間的路由。 二、BGP並非要找到具體的網絡信息,而是提供可以用與找到自治系統的信息。 而運行於自治系統內部的路由協議,用於找到

分布式Redis常見問題解決方案

百萬 要求 軟件企業 參數 沒有 cpu redis 休眠 產生 前言考慮到絕大部分寫業務的程序員,在實際開發中使用 Redis 的時候,只會 Set Value 和 Get Value 兩個操作,對 Redis 整體缺乏一個認知。 所以我鬥膽以 Redis 為題材,對 R

《修煉之道:.NET開發要點》讀書筆記(

後幾章的習題 1.非同步呼叫開始後,什麼時候才能使用非同步執行的結果? A:最好在EndInvoke()方法返回之後才能使用非同步執行的結果,其它時候不能保證非同步呼叫已完成。   2.委託的非同步呼叫開始後(即呼叫BeginInvoke方法後),EndInvoke方法是否可以在同一執行緒中

《Oracle PL/SQL例項》學習筆記26——優化PL/SQL(第部分——子程式內聯)

本章內容: 1. PL/SQL調優工具 2. PL/SQL優化級別 3. 子程式內聯   程式碼如下: 1. 檢視dbmshptab.sql指令碼內容 Rem Rem $Header: rdbms/admin/dbmshptab.sql /main/4 20

Mybatis學習總結之簡化sql對映xml檔案中的引用解決欄位名與實體類屬性名不相同的衝突

一、為實體類定義別名,簡化sql對映xml檔案中的引用 我們在sql對映xml檔案中的引用實體類時,需要寫上實體類的全類名(包名+類名),如下:parameterType="com.aiit.pojo.User"這裡寫的實體類User的全類名com.aiit.pojo.User, <i