封面:洛小汐
作者:潘潘
做大事和做小事的難度是一樣的损肛。兩者都會(huì)消耗你的時(shí)間和精力厢破,所以如果決心做事,就要做大事治拿,要確保你的夢(mèng)想值得追求摩泪,未來的收獲可以配得上你的努力。
前言
上一篇文章 《Mybatis系列全解(三):Mybatis簡(jiǎn)單CRUD使用介紹》 忍啤,我們基本上手了 Mybatis 的增刪改查操作加勤,也感受到 Mybatis 的簡(jiǎn)單高效舒美,但是肯定有部分朋友對(duì)于 Mybatis 的配置文件只是了解基本組成和大致用法同波,尚無(wú)一套完整的結(jié)構(gòu)記憶鳄梅,所以本篇文章我們將詳細(xì)的介紹 Mybatis 的配置全貌,畢竟 Mybatis 的配置文件對(duì)于整個(gè) Mybatis 體系的構(gòu)建與支撐有著深遠(yuǎn)的影響未檩。
Mybatis系列全解腦圖分享戴尸,持續(xù)更新中
Mybaits系列全解 (持續(xù)更新)
- Mybatis系列全解(一):手寫一套持久層框架
- Mybatis系列全解(二):Mybatis簡(jiǎn)介與環(huán)境搭建
- Mybatis系列全解(三):Mybatis簡(jiǎn)單CRUD使用介紹
- Mybatis系列全解(四):全網(wǎng)最全!Mybatis配置文件XML全貌詳解
- Mybatis系列全解(五):全網(wǎng)最全冤狡!詳解Mybatis的Mapper映射文件
- Mybatis系列全解(六):Mybatis最硬核的API你知道幾個(gè)孙蒙?
- Mybatis系列全解(七):Dao層兩種實(shí)現(xiàn)方式
- Mybatis系列全解(八):Mybatis的動(dòng)態(tài)SQL
- Mybatis系列全解(九):Mybatis的復(fù)雜映射
- Mybatis系列全解(十):Mybatis注解開發(fā)
- Mybatis系列全解(十一):Mybatis緩存全解
- Mybatis系列全解(十二):Mybatis插件開發(fā)
- Mybatis系列全解(十三):Mybatis代碼生成器
- Mybatis系列全解(十四):Spring集成Mybatis
- Mybatis系列全解(十五):SpringBoot集成Mybatis
- Mybatis系列全解(十六):Mybatis源碼剖析
目錄
1、為什么要使用配置文件
2悲雳、Mybatis 配置全貌
3挎峦、XML 核心配置
4、XML 映射文件
5合瓢、總結(jié)
為什么要使用配置文件
試想坦胶,如果沒有配置文件,我們的應(yīng)用程序?qū)⒅荒苎刂潭ǖ淖藨B(tài)運(yùn)行晴楔,幾乎不能做任何動(dòng)態(tài)的調(diào)整顿苇,那么這不是一套完美的設(shè)計(jì),因?yàn)槲覀兿M麚碛懈鼘捀`活的操作空間和更多的兼容度税弃,同時(shí)也能解決硬編碼等問題纪岁,所以我們需要有配置文件,對(duì)應(yīng)用程序進(jìn)行參數(shù)預(yù)設(shè)和設(shè)置初始化工作则果。
那我們?yōu)楹午娗閄ML幔翰?
首先漩氨,當(dāng)然是 XML 配置文件本身就足夠優(yōu)秀,格式規(guī)范遗增,存儲(chǔ)小才菠,跨平臺(tái),讀取快...等等贡定,所謂窈窕淑女,誰(shuí)人不愛可都。
其次缓待,也是一個(gè)重要影響因素,就是各大領(lǐng)域大佬的支持渠牲,像微軟旋炒、像Java系...等等,世上本無(wú)路签杈,只是走的人多了瘫镇,也就成了路 ( 這句話是魯迅老先生說的)。
所以答姥,Mybatis選擇搭配XML配置铣除,實(shí)屬合理。
Mybatis 配置全貌
Mybatis框架本身鹦付,理論上就一個(gè)配置文件尚粘,其實(shí)也只需要一個(gè)配置文件,即mybatis-config.xml (當(dāng)然文件名允許自由命名)敲长,只不過這個(gè)配置文件其中的一個(gè)屬性mappers(映射器)郎嫁,由于可能產(chǎn)生過多的SQL映射文件,于是我們物理上單獨(dú)拓展出來祈噪,允許使用者定義任意數(shù)量的 xxxMapper.xml 映射文件泽铛。
把SQL映射文件單獨(dú)配置,是有好處的辑鲤,一是靈活度上允許任意拓展盔腔,二也避免了其它無(wú)需經(jīng)常變動(dòng)的屬性配置遭遇誤改。
我們看看Mybatis官網(wǎng)給出的配置文件層次結(jié)構(gòu):
- configuration(配置)
- properties(屬性)
- settings(設(shè)置)
- typeAliases(類型別名)
- 三種別名定義方式
- typeHandlers(類型處理器)
- 自定義類型處理器
- objectFactory(對(duì)象工廠)
- plugins(插件)
- environments(環(huán)境配置)
- environment(環(huán)境變量)
- transactionManager(事務(wù)管理器)
- dataSource(數(shù)據(jù)源)
- 三種支持?jǐn)?shù)據(jù)源與自定義數(shù)據(jù)源
- environment(環(huán)境變量)
- databaseIdProvider(數(shù)據(jù)庫(kù)廠商標(biāo)識(shí))
- mappers(映射器)
實(shí)際配置文件XML內(nèi)容如下遂填,除了約束頭 <?xml> 與 <!DOCTYPE>铲觉,
其余標(biāo)簽元素都是 Mybatis 的核心配置屬性 :
<?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>
<!-- 1、屬性:例如jdbc.properties -->
<properties resource="jdbc.properties"></properties>
<!-- 2吓坚、設(shè)置:定義全局性設(shè)置撵幽,例如開啟二級(jí)緩存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 3、類型名稱:為一些類定義別名 -->
<typeAliases>
<typeAlias type="com.panshenlian.pojo.User" alias="user"></typeAlias>
</typeAliases>
<!-- 4礁击、類型處理器:定義Java類型與數(shù)據(jù)庫(kù)中的數(shù)據(jù)類型之間的轉(zhuǎn)換關(guān)系 -->
<typeHandlers></typeHandlers>
<!-- 5盐杂、對(duì)象工廠 -->
<objectFactory type=""></objectFactory>
<!-- 6逗载、插件:mybatis的插件,支持自定義插件 -->
<plugins>
<plugin interceptor=""></plugin>
</plugins>
<!-- 7链烈、環(huán)境:配置mybatis的環(huán)境 -->
<environments default="development">
<!-- 環(huán)境變量:支持多套環(huán)境變量厉斟,例如開發(fā)環(huán)境、生產(chǎn)環(huán)境 -->
<environment id="development">
<!-- 事務(wù)管理器:默認(rèn)JDBC -->
<transactionManager type="JDBC" />
<!-- 數(shù)據(jù)源:使用連接池强衡,并加載mysql驅(qū)動(dòng)連接數(shù)據(jù)庫(kù) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<!-- 8擦秽、數(shù)據(jù)庫(kù)廠商標(biāo)識(shí) -->
<databaseIdProvider type=""></databaseIdProvider>
<!-- 9、映射器:指定映射文件或者映射類 -->
<mappers>
<mapper resource="UserMapper.xml" />
</mappers>
</configuration>
必須注意:Mybatis配置文件的屬性位置順序是 固定 的漩勤,不允許 顛倒順序感挥,否則 Mybatis 在解析 XML 文件的時(shí)候就會(huì)拋出異常,這個(gè)與 Mybatis 框架啟動(dòng)加載配置信息順序有關(guān)越败,后續(xù)我們?cè)创a分析會(huì)講到触幼。
以上基本能夠清晰看明白 Mybatis 配置文件的層次結(jié)構(gòu)關(guān)系,我們簡(jiǎn)單畫一張腦圖:
基本是需要我們掌握 9 大頂級(jí)元素配置究飞,其中標(biāo)記 橘紅色 的屬性配置置谦,由于涉及 插件 和 動(dòng)態(tài)SQL ,插件配置可以應(yīng)用于分頁(yè)與功能增強(qiáng)等亿傅,動(dòng)態(tài)SQL例如 if 標(biāo)簽媒峡、where 標(biāo)簽、foreach標(biāo)簽等葵擎,初步理解為應(yīng)用于SQL語(yǔ)句拼接丝蹭。這兩塊屬于 Mybatis 的兩個(gè)特性,我們后續(xù)單獨(dú)詳細(xì)進(jìn)行梳理討論坪蚁。
XML 核心配置
我們的核心配置文件 configuration(配置)作為最頂級(jí)節(jié)點(diǎn)奔穿,其余 9 大屬性都必須嵌套在其內(nèi),對(duì)于內(nèi)部 9 大節(jié)點(diǎn)敏晤,我們逐一講解:
1贱田、properties(屬性)
屬性標(biāo)簽,顯而易見就是提供屬性配置嘴脾,可進(jìn)行動(dòng)態(tài)替換男摧,一般可以在 Java 屬性文件中配置,例如 jdbc.properties 配置文件 译打,或通過 properties 元素標(biāo)簽中的子元素 property 來指定配置耗拓。
舉例我們需要配置數(shù)據(jù)源信息,采用 property 標(biāo)簽可以這樣配置:
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/myDB"/>
<property name="username" value="user1"/>
<property name="password" value="123456"/>
</properties>
設(shè)置好的屬性可以在整個(gè)配置文件中用來替換需要?jiǎng)討B(tài)配置的屬性值奏司。比如:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
或者我們使用 Java 中的屬性配置文件乔询,把屬性配置元素具體化到一個(gè)屬性文件中,并且使用屬性文件的 key 名作為占位符韵洋。例如 jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc\:mysql\://127.0.0.1\:3306/myDB
username=root
password=123456
使用時(shí)我們把屬性文件引入竿刁,并使用文件中定義的占位符黄锤,例如 db.driver :
<!-- 引入屬性配置文件 -->
<properties resource="jdbc.properties"></properties>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
但是問題來了,當(dāng)我們既使用 *.properties 配置文件食拜,同時(shí)又設(shè)置了 property 元素值鸵熟,Mybatis 會(huì)使用哪邊配置的屬性值呢? 例如這種情況 :
<properties resource="jdbc.properties">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/myDB"/>
<property name="username" value="user1"/>
<property name="password" value="123456"/>
</properties>
這里负甸,如果在 property 標(biāo)簽元素與 jdbc.properties 文件中同時(shí)存在相同屬性流强,那么屬性文件將會(huì)覆蓋 property 標(biāo)簽元素的屬性,例如最終 username屬性值會(huì)使用 jdbc.properties 文件中設(shè)置的 root呻待,而不會(huì)使用屬性元素設(shè)置的 user1 煮盼。這樣實(shí)際為配置提供了諸多靈活選擇。
另外带污,properties 元素允許配置 resource 屬性或 url 屬性,只能二選一香到,要么使用 resource 指定本地的配置文件鱼冀,要么使用 url 指定遠(yuǎn)程的配置文件,因?yàn)?Mybatis 在加載配置時(shí)悠就,如果發(fā)現(xiàn) url 與 resource 同時(shí)存在千绪,會(huì)拋出異常禁止。
<!-- 配置resource-->
<properties resource="xxx.properties">
<property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>
<!-- 配置url-->
<properties url="http://xxxx">
<property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>
還有一種情況梗脾,像 Mybatis 在解析配置的時(shí)候荸型,也可以在 Java 代碼中構(gòu)建屬性 java.util.Properties 屬性對(duì)象并傳遞到 SqlSessionFactoryBuilder.build() 方法中,例如:
// 構(gòu)建屬性對(duì)象
Properties props = new Properties();
props.setProperty("driver","com.mysql.jdbc.Driver");
props.setProperty("url","jdbc:mysql://127.0.0.1:3306/myDB");
props.setProperty("username","user1");
props.setProperty("password","123456");
// 傳遞屬性構(gòu)建 SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
那么這三種方式都允許配置炸茧,那在屬性配置重復(fù)的情況下瑞妇,優(yōu)先級(jí)別是怎樣呢?
properties 優(yōu)先級(jí)
1梭冠、第一優(yōu)先級(jí):在 Java 代碼中構(gòu)建的 properties 屬性對(duì)象辕狰;
2、第二優(yōu)先級(jí):通過屬性 resource 或 url 讀取到的本地文件或遠(yuǎn)程文件控漠;
3蔓倍、第三優(yōu)先級(jí):直接在 properties 內(nèi)部子標(biāo)簽元素 property 中設(shè)置的屬性。
注意盐捷,在實(shí)際開發(fā)中偶翅,為了避免給后期維護(hù)造成困擾,建議使用單一種配置方式碉渡。
2聚谁、settings(設(shè)置)
settings 標(biāo)簽元素,是 MyBatis 中極為重要的調(diào)整設(shè)置滞诺,它們會(huì)動(dòng)態(tài)改變 MyBatis 的運(yùn)行時(shí)行為垦巴,這些配置就像 Mybatis 內(nèi)置的許多功能媳搪,當(dāng)你需要使用時(shí)可以根據(jù)需要靈活調(diào)整,并且 settings 能配置的東西特別多骤宣,我們先來一起看看秦爆,一個(gè)完整的屬性配置示例:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
<... more .../>
</settings>
-
屬性cacheEnabled
- 全局性地開啟或關(guān)閉所有映射器配置文件中已配置的任何緩存
- 支持 true | false
- 默認(rèn) true
-
屬性lazyLoadingEnabled
- 延遲加載的全局開關(guān)。當(dāng)開啟時(shí)憔披,所有關(guān)聯(lián)對(duì)象都會(huì)延遲加載等限。 特定關(guān)聯(lián)關(guān)系中可通過設(shè)置 fetchType 屬性來覆蓋該項(xiàng)的開關(guān)狀態(tài)。
- 支持 true | false
- 默認(rèn) false
-
屬性 aggressiveLazyLoading
- 開啟時(shí)芬膝,任一方法的調(diào)用都會(huì)加載該對(duì)象的所有延遲加載屬性望门。 否則,每個(gè)延遲加載屬性會(huì)按需加載(參考 lazyLoadTriggerMethods)锰霜。
- 支持 true | false
- 默認(rèn) false (在 3.4.1 及之前的版本中默認(rèn)為 true)
-
屬性 multipleResultSetsEnabled
- 是否允許單個(gè)語(yǔ)句返回多結(jié)果集(需要數(shù)據(jù)庫(kù)驅(qū)動(dòng)支持)筹误。
- 支持 true | false
- 默認(rèn) true
-
屬性 useColumnLabel
- 使用列標(biāo)簽代替列名。實(shí)際表現(xiàn)依賴于數(shù)據(jù)庫(kù)驅(qū)動(dòng)癣缅,具體可參考數(shù)據(jù)庫(kù)驅(qū)動(dòng)的相關(guān)文檔厨剪,或通過對(duì)比測(cè)試來觀察。
- 支持 true | false
- 默認(rèn) true
-
屬性 useGeneratedKeys
- 允許 JDBC 支持自動(dòng)生成主鍵友存,需要數(shù)據(jù)庫(kù)驅(qū)動(dòng)支持祷膳。如果設(shè)置為 true,將強(qiáng)制使用自動(dòng)生成主鍵屡立。盡管一些數(shù)據(jù)庫(kù)驅(qū)動(dòng)不支持此特性直晨,但仍可正常工作(如 Derby)。
- 支持 true | false
- 默認(rèn) false
-
屬性 autoMappingBehavior
- 指定 MyBatis 應(yīng)如何自動(dòng)映射列到字段或?qū)傩浴?NONE 表示關(guān)閉自動(dòng)映射膨俐;PARTIAL 只會(huì)自動(dòng)映射沒有定義嵌套結(jié)果映射的字段勇皇。 FULL 會(huì)自動(dòng)映射任何復(fù)雜的結(jié)果集(無(wú)論是否嵌套)。
- 支持 NONE, PARTIAL, FULL
- 默認(rèn) PARTIAL
-
屬性 autoMappingUnknownColumnBehavior
- 指定發(fā)現(xiàn)自動(dòng)映射目標(biāo)未知列(或未知屬性類型)的行為焚刺。
- NONE: 不做任何反應(yīng)
- WARNING: 輸出警告日志( org.apache.ibatis.session.AutoMappingUnknownColumnBehavior 的日志等級(jí)必須設(shè)置為 WARN)
- FAILING: 映射失敗 (拋出 SqlSessionException)
- 支持 NONE, WARNING, FAILING
- 默認(rèn) NONE
- 指定發(fā)現(xiàn)自動(dòng)映射目標(biāo)未知列(或未知屬性類型)的行為焚刺。
-
屬性 defaultExecutorType
- 配置默認(rèn)的執(zhí)行器儒士。SIMPLE 就是普通的執(zhí)行器;REUSE 執(zhí)行器會(huì)重用預(yù)處理語(yǔ)句(PreparedStatement)檩坚; BATCH 執(zhí)行器不僅重用語(yǔ)句還會(huì)執(zhí)行批量更新着撩。
- 支持 SIMPLE REUSE BATCH
- 默認(rèn) SIMPLE
-
屬性 defaultStatementTimeout
- 設(shè)置超時(shí)時(shí)間,它決定數(shù)據(jù)庫(kù)驅(qū)動(dòng)等待數(shù)據(jù)庫(kù)響應(yīng)的秒數(shù)匾委。
- 支持 任意正整數(shù)
- 默認(rèn) 未設(shè)置 (null)
-
屬性 defaultFetchSize
- 動(dòng)的結(jié)果集獲取數(shù)量(fetchSize)設(shè)置一個(gè)建議值拖叙。此參數(shù)只可以在查詢?cè)O(shè)置中被覆蓋。
- 支持 任意正整數(shù)
- 默認(rèn) 未設(shè)置 (null)
-
屬性 defaultResultSetType
- 指定語(yǔ)句默認(rèn)的滾動(dòng)策略赂乐。(新增于 3.5.2)
- 支持 FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未設(shè)置)
- 默認(rèn) 未設(shè)置 (null)
-
屬性 safeRowBoundsEnabled
- 是否允許在嵌套語(yǔ)句中使用分頁(yè)(RowBounds)薯鳍。如果允許使用則設(shè)置為 false。
- 支持 true | false
- 默認(rèn) false
-
屬性 safeResultHandlerEnabled
- 是否允許在嵌套語(yǔ)句中使用結(jié)果處理器(ResultHandler)。如果允許使用則設(shè)置為 false挖滤。
- 支持 true | false
- 默認(rèn) true
-
屬性 mapUnderscoreToCamelCase
- 是否開啟駝峰命名自動(dòng)映射崩溪,即從經(jīng)典數(shù)據(jù)庫(kù)列名 A_COLUMN 映射到經(jīng)典 Java 屬性名 aColumn。
- 支持 true | false
- 默認(rèn) false
-
屬性 localCacheScope
- MyBatis 利用本地緩存機(jī)制(Local Cache)防止循環(huán)引用和加速重復(fù)的嵌套查詢斩松。 默認(rèn)值為 SESSION伶唯,會(huì)緩存一個(gè)會(huì)話中執(zhí)行的所有查詢。 若設(shè)置值為 STATEMENT惧盹,本地緩存將僅用于執(zhí)行語(yǔ)句乳幸,對(duì)相同 SqlSession 的不同查詢將不會(huì)進(jìn)行緩存。
- 支持 SESSION | STATEMENT
- 默認(rèn) SESSION
-
屬性 jdbcTypeForNull
- 當(dāng)沒有為參數(shù)指定特定的 JDBC 類型時(shí)钧椰,空值的默認(rèn) JDBC 類型粹断。 某些數(shù)據(jù)庫(kù)驅(qū)動(dòng)需要指定列的 JDBC 類型,多數(shù)情況直接用一般類型即可嫡霞,比如 NULL瓶埋、VARCHAR 或 OTHER。
- JdbcType 常量诊沪,常用值:NULL养筒、VARCHAR 或 OTHER。
- 默認(rèn) OTHER
-
屬性 lazyLoadTriggerMethods
- 指定對(duì)象的哪些方法觸發(fā)一次延遲加載娄徊。
- 支持 用逗號(hào)分隔的方法列表。
- 默認(rèn) equals,clone,hashCode,toString
-
屬性 defaultScriptingLanguage
- 指定動(dòng)態(tài) SQL 生成使用的默認(rèn)腳本語(yǔ)言盾戴。
- 支持 一個(gè)類型別名或全限定類名寄锐。
- 默認(rèn) org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
-
屬性 defaultEnumTypeHandler
- 指定 Enum 使用的默認(rèn) TypeHandler 。(新增于 3.4.5)
- 支持 一個(gè)類型別名或全限定類名尖啡。
- 默認(rèn) org.apache.ibatis.type.EnumTypeHandler
-
屬性 callSettersOnNulls
- 指定當(dāng)結(jié)果集中值為 null 的時(shí)候是否調(diào)用映射對(duì)象的 setter(map 對(duì)象時(shí)為 put)方法橄仆,這在依賴于 Map.keySet() 或 null 值進(jìn)行初始化時(shí)比較有用。注意基本類型(int衅斩、boolean 等)是不能設(shè)置成 null 的盆顾。
- 支持 true | false
- 默認(rèn) false
-
屬性 returnInstanceForEmptyRow
- 當(dāng)返回行的所有列都是空時(shí),MyBatis默認(rèn)返回 null畏梆。 當(dāng)開啟這個(gè)設(shè)置時(shí)您宪,MyBatis會(huì)返回一個(gè)空實(shí)例。 請(qǐng)注意奠涌,它也適用于嵌套的結(jié)果集(如集合或關(guān)聯(lián))宪巨。(新增于 3.4.2)
- 支持 true | false
- 默認(rèn) false
-
屬性 logPrefix
- 指定 MyBatis 增加到日志名稱的前綴。
- 支持 任何字符串
- 默認(rèn) 未設(shè)置
-
屬性 logImpl
- 指定 MyBatis 所用日志的具體實(shí)現(xiàn)溜畅,未指定時(shí)將自動(dòng)查找捏卓。
- 支持 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
- 默認(rèn) 未設(shè)置
-
屬性 proxyFactory
- 指定 Mybatis 創(chuàng)建可延遲加載對(duì)象所用到的代理工具。
- 支持 CGLIB | JAVASSIST
- 默認(rèn) JAVASSIST (MyBatis 3.3 以上)
-
屬性 vfsImpl
- 指定 VFS 的實(shí)現(xiàn)
- 支持 自定義 VFS 的實(shí)現(xiàn)的類全限定名慈格,以逗號(hào)分隔怠晴。
- 默認(rèn) 未設(shè)置
-
屬性 useActualParamName
- 允許使用方法簽名中的名稱作為語(yǔ)句參數(shù)名稱遥金。 為了使用該特性,你的項(xiàng)目必須采用 Java 8 編譯蒜田,并且加上 -parameters 選項(xiàng)稿械。(新增于 3.4.1)
- 支持 true | false
- 默認(rèn) true
-
屬性 configurationFactory
- 指定一個(gè)提供 Configuration 實(shí)例的類。 這個(gè)被返回的 Configuration 實(shí)例用來加載被反序列化對(duì)象的延遲加載屬性值物邑。 這個(gè)類必須包含一個(gè)簽名為static Configuration getConfiguration() 的方法溜哮。(新增于 3.2.3)
- 支持 一個(gè)類型別名或完全限定類名。
- 默認(rèn) 未設(shè)置
-
屬性 shrinkWhitespacesInSql
- 從SQL中刪除多余的空格字符色解。請(qǐng)注意茂嗓,這也會(huì)影響SQL中的文字字符串。 (新增于 3.5.5)
- 支持 true | false
- 默認(rèn) false
-
屬性 defaultSqlProviderType
- 指定一個(gè)本身?yè)聿樵兎椒ǖ念悾?從 3.5.6 開始 )科阎,這個(gè)類可以配置在注解 @SelectProvider 的 type 屬性值上述吸。
- 支持 一個(gè)類型別名或完全限定類名。
- 默認(rèn) 未設(shè)置
settings 支持了特別多功能支持锣笨,其實(shí)常規(guī)開發(fā)中使用到的屬性項(xiàng)不會(huì)特別多蝌矛,除非項(xiàng)目有特殊要求,所以建議大家把這些設(shè)置當(dāng)做字典即可错英,不必詳記 每一個(gè)屬性使用入撒,需要時(shí)翻閱研讀。
3椭岩、typeAliases(類型別名)
類型別名可以給 Java 類型設(shè)置一個(gè)簡(jiǎn)稱茅逮。 它僅用于 XML 配置,意在降低冗余的全限定類名書寫判哥,因?yàn)闀鴮戭惖娜薅L(zhǎng)了献雅,我們希望有一個(gè)簡(jiǎn)稱來指代它。類型別名在 Mybatis 中分為 系統(tǒng)內(nèi)置 和 用戶自定義 兩類塌计,Mybatis 會(huì)在解析配置文件時(shí)把 typeAliases 實(shí)例存儲(chǔ)進(jìn)入 Configuration 對(duì)象中挺身,需要使用時(shí)直接獲取。
一般我們可以自定義別名锌仅,例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
像這樣配置時(shí)章钾,我們就可以在任何需要使用 domain.blog.Author 的地方,直接使用別名 author 热芹。
但是伍玖,如果遇到項(xiàng)目中特別多 Java 類需要配置別名,怎么更快的設(shè)置呢?
可以指定一個(gè)包名進(jìn)行掃描,MyBatis 會(huì)在包名下面掃描需要的 Java Bean值桩,比如:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
每一個(gè)在包 domain.blog 中的 Java Bean挺物,在沒有注解的情況下椰棘,會(huì)使用 Bean 的首字母小寫的非限定類名來作為它的別名纺棺。 比如 domain.blog.Author 的別名為 author;若有 注解 邪狞,則別名為其自定義的注解值祷蝌。見下面的例子:
@Alias("myAuthor")
public class Author {
...
}
Mybatis 已經(jīng)為許多常見的 Java 類型內(nèi)建了相應(yīng)的類型別名。下面就是一些為常見的 Java 類型內(nèi)建的類型別名帆卓。它們都是不區(qū)分大小寫的巨朦,注意,為了應(yīng)對(duì)原始類型的命名重復(fù)剑令,采取了特殊的命名風(fēng)格糊啡,可以發(fā)現(xiàn) 基本類型 的別名前綴都有下劃線 ‘_’,而基本類型的 包裝類 則沒有吁津,這個(gè)需要注意:
- 別名 _byte棚蓄,對(duì)應(yīng)的類型是:byte
- 別名 _long,對(duì)應(yīng)的類型是:long
- 別名 _short碍脏,對(duì)應(yīng)的類型是:short
- 別名 _int梭依,對(duì)應(yīng)的類型是:int
- 別名 _integer,對(duì)應(yīng)的類型是:int
- 別名 _double典尾,對(duì)應(yīng)的類型是:double
- 別名 _float役拴,對(duì)應(yīng)的類型是:float
- 別名 _boolean,對(duì)應(yīng)的類型是:boolean
- 別名 string钾埂,對(duì)應(yīng)的類型是:String
- 別名 byte河闰,對(duì)應(yīng)的類型是:Byte
- 別名 long,對(duì)應(yīng)的類型是:Long
- 別名 short勃教,對(duì)應(yīng)的類型是:Short
- 別名 int淤击,對(duì)應(yīng)的類型是:Integer
- 別名 integer匠抗,對(duì)應(yīng)的類型是:Integer
- 別名 double故源,對(duì)應(yīng)的類型是:Double
- 別名 float,對(duì)應(yīng)的類型是:Float
- 別名 boolean汞贸,對(duì)應(yīng)的類型是:Boolean
- 別名 date绳军,對(duì)應(yīng)的類型是:Date
- 別名 decimal,對(duì)應(yīng)的類型是:BigDecimal
- 別名 bigdecimal矢腻,對(duì)應(yīng)的類型是:BigDecimal
- 別名 object门驾,對(duì)應(yīng)的類型是:Object
- 別名 map,對(duì)應(yīng)的類型是:Map
- 別名 hashmap多柑,對(duì)應(yīng)的類型是:HashMap
- 別名 list奶是,對(duì)應(yīng)的類型是:List
- 別名 arraylist,對(duì)應(yīng)的類型是:ArrayList
- 別名 collection,對(duì)應(yīng)的類型是:Collection
- 別名 iterator聂沙,對(duì)應(yīng)的類型是:Iterator
我們可以通過源碼查看內(nèi)置的類型別名的注冊(cè)信息秆麸。
具體源碼路徑在 org.apache.ibatis.type.TypeAliasRegistry # TypeAliasRegistry() :
public TypeAliasRegistry() {
registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
registerAlias("ResultSet", ResultSet.class);
}
別名是不區(qū)分大小寫的,同時(shí)也支持?jǐn)?shù)組類型及汉,只需要加 “[]” 即可使用沮趣,比如 Long 數(shù)組別名我們可以用 long[] 直接代替,例如在實(shí)際開發(fā)中坷随,int 房铭、INT 、integer 温眉、INTEGER 都是代表 Integer 缸匪, 這里主要由于 MyBatis 在注冊(cè)別名的時(shí)候會(huì)全部轉(zhuǎn)為小寫字母進(jìn)行存儲(chǔ),另外以上列表 無(wú)需牢記芍殖,僅僅在需要使用的時(shí)候查閱即可豪嗽,基本也都可以看得明白。
4豌骏、typeHandlers(類型處理器)
MyBatis 在設(shè)置預(yù)處理SQL語(yǔ)句(PreparedStatement)中所需要的 參數(shù) 或從 結(jié)果集 ResultSet 中獲取對(duì)象時(shí)龟梦, 都會(huì)用類型處理器將獲取到的值以合適的方式轉(zhuǎn)換成 Java 類型。
類型處理器窃躲,主要用于處理 Java 類型與 JDBC 類型的映射匹配關(guān)系處理计贰,下表描述了一些默認(rèn)的類型處理器。
- 類型處理器 BooleanTypeHandler
- Java 類型:java.lang.Boolean, boolean
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 BOOLEAN
- 類型處理器 ByteTypeHandler
- Java 類型:java.lang.Byte, byte
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 BYTE
- 類型處理器 ShortTypeHandler
- Java 類型:java.lang.Short, short
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 SMALLINT
- 類型處理器 IntegerTypeHandler
- Java 類型:java.lang.Integer, int
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 INTEGER
- 類型處理器 LongTypeHandler
- Java 類型:java.lang.Long, long
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 BIGINT
- 類型處理器 FloatTypeHandler
- Java 類型:java.lang.Float, float
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 FLOAT
- 類型處理器 DoubleTypeHandler
- Java 類型:java.lang.Double, double
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 DOUBLE
- 類型處理器 BigDecimalTypeHandler
- Java 類型:java.math.BigDecimal
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 DECIMAL
- 類型處理器 StringTypeHandler
- Java 類型:java.lang.String
- JDBC 類型:CHAR, VARCHAR
- 類型處理器 ClobReaderTypeHandler
- Java 類型:java.io.Reader
- JDBC 類型:-
- 類型處理器 ClobTypeHandler
- Java 類型:java.lang.String
- JDBC 類型:CLOB, LONGVARCHAR
- 類型處理器 NStringTypeHandler
- Java 類型:java.lang.String
- JDBC 類型:NVARCHAR, NCHAR
- 類型處理器 NClobTypeHandler
- Java 類型:java.lang.String
- JDBC 類型:NCLOB
- 類型處理器 BlobInputStreamTypeHandler
- Java 類型:java.io.InputStream
- JDBC 類型:-
- 類型處理器 ByteArrayTypeHandler
- Java 類型:byte[]
- JDBC 類型:數(shù)據(jù)庫(kù)兼容的字節(jié)流類型
- 類型處理器 BlobTypeHandler
- Java 類型:byte[]
- JDBC 類型:BLOB, LONGVARBINARY
- 類型處理器 DateTypeHandler
- Java 類型:java.util.Date
- JDBC 類型:TIMESTAMP
- 類型處理器 DateOnlyTypeHandler
- Java 類型:java.util.Date
- JDBC 類型:DATE
- 類型處理器 TimeOnlyTypeHandler
- Java 類型:java.util.Date
- JDBC 類型:TIME
- 類型處理器 SqlTimestampTypeHandler
- Java 類型:java.sql.Timestamp
- JDBC 類型:TIMESTAMP
- 類型處理器 SqlDateTypeHandler
- Java 類型:java.sql.Date
- JDBC 類型:DATE
- 類型處理器 SqlTimeTypeHandler
- Java 類型:java.sql.Time
- JDBC 類型:TIME
- 類型處理器 ObjectTypeHandler
- Java 類型:Any
- JDBC 類型:OTHER 或未指定類型
- 類型處理器 EnumTypeHandler
- Java 類型:Enumeration Type
- JDBC 類型:VARCHAR 或任何兼容的字符串類型蒂窒,用來存儲(chǔ)枚舉的名稱(而不是索引序數(shù)值)
- 類型處理器 EnumOrdinalTypeHandler
- Java 類型:Enumeration Type
- JDBC 類型:任何兼容的 NUMERIC 或 DOUBLE 類型躁倒,用來存儲(chǔ)枚舉的序數(shù)值(而不是名稱)。
- 類型處理器 SqlxmlTypeHandler
- Java 類型:java.lang.String
- JDBC 類型:SQLXML
- 類型處理器 InstantTypeHandler
- Java 類型:java.time.Instant
- JDBC 類型:TIMESTAMP
- 類型處理器 LocalDateTimeTypeHandler
- Java 類型:java.time.LocalDateTime
- JDBC 類型:TIMESTAMP
- 類型處理器 LocalDateTypeHandler
- Java 類型:java.time.LocalDate
- JDBC 類型:DATE
- 類型處理器 LocalTimeTypeHandler
- Java 類型:java.time.LocalTime
- JDBC 類型:TIME
- 類型處理器 OffsetDateTimeTypeHandler
- Java 類型:java.time.OffsetDateTime
- JDBC 類型:TIMESTAMP
- 類型處理器 OffsetTimeTypeHandler
- Java 類型:java.time.OffsetTime
- JDBC 類型:TIME
- 類型處理器 ZonedDateTimeTypeHandler
- Java 類型:java.time.ZonedDateTime
- JDBC 類型:TIMESTAMP
- 類型處理器 YearTypeHandler
- Java 類型:java.time.Year
- JDBC 類型:INTEGER
- 類型處理器 MonthTypeHandler
- Java 類型:java.time.Month
- JDBC 類型:INTEGER
- 類型處理器 YearMonthTypeHandler
- Java 類型:java.time.YearMonth
- JDBC 類型:VARCHAR 或 LONGVARCHAR
- 類型處理器 JapaneseDateTypeHandler
- Java 類型:java.time.chrono.JapaneseDate
- JDBC 類型:DATE
我們可以通過源碼查看內(nèi)置的類型別名的注冊(cè)信息洒琢。
具體源碼路徑在 org.apache.ibatis.type.TypeHandlerRegistry # TypeHandlerRegistry() :
public TypeHandlerRegistry() {
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
// mybatis-typehandlers-jsr310
if (Jdk.dateAndTimeApiExists) {
Java8TypeHandlersRegistrar.registerDateAndTimeHandlers(this);
}
// issue #273
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
}
從 3.4.5 開始秧秉,MyBatis 默認(rèn)支持 JSR-310(日期和時(shí)間 API) ,可以在以上源碼上看到新增支持。
一般衰抑,你可以重寫已有的類型處理器象迎,
或根據(jù)業(yè)務(wù)需要?jiǎng)?chuàng)建你自己的類型處理器,
以處理不支持的類型或非標(biāo)準(zhǔn)的類型呛踊。
具體做法為:
1砾淌、實(shí)現(xiàn) org.apache.ibatis.type.TypeHandler
接口;
2谭网、繼承 org.apache.ibatis.type.BaseTypeHandler
類汪厨。
本身 BaseTypeHandler 類作為抽象類就已經(jīng)實(shí)現(xiàn)了 TypeHandler 接口。
所以我們看到接口 TypeHandler 定義了四個(gè)方法:
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;
}
從方法名 setParameter 和 getResult 我們就可以知道愉择,是發(fā)生在預(yù)編譯時(shí)設(shè)置參數(shù)(增刪改查傳入?yún)?shù))與查詢結(jié)果集后轉(zhuǎn)換為 Java 類型時(shí)劫乱,類型處理器發(fā)揮作用织中。
具體實(shí)現(xiàn)如下,先自定義類型處理器類 MyExampleTypeHandler :
// MyExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyExampleTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}
自定義類已設(shè)定:JdbcType.VARCHAR 與 String 類做映射轉(zhuǎn)換(注解和泛型已體現(xiàn))衷戈。
其次抠璃,在核心配置文件中設(shè)置類型處理器:
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.mybatis.example.MyExampleTypeHandler"/>
</typeHandlers>
或者不使用注解方式的話,取消 @MappedJdbcTypes(JdbcType.VARCHAR) 注解脱惰,直接在 xml 配置中指定 jdbcType 與 javaType 映射 :
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler jdbcType="VARCHAR" javaType="string" handler="org.mybatis.example.MyExampleTypeHandler"/>
</typeHandlers>
記住搏嗡, typeHandler 的配置方式優(yōu)先級(jí)高于注解配置方式。
這里拉一,自定義類型處理器將會(huì)覆蓋已有的處理 Java String 類型的屬性以及 VARCHAR 類型的參數(shù)和結(jié)果的類型處理器采盒,基本以上步驟就已經(jīng)自定了 JdbcType.VARCHAR 與 String類做映射轉(zhuǎn)換。
其實(shí)到這里蔚润,我們基本也就完成了類型處理器的自定義轉(zhuǎn)換磅氨,但是有一種情況,就是我們希望我們自定義的類型處理器只處理某一個(gè) Java 實(shí)體中的 JdbcType.VARCHAR 與 String 類映射轉(zhuǎn)換嫡纠,其它實(shí)體的處理還是使用系統(tǒng)內(nèi)置的轉(zhuǎn)換烦租,很簡(jiǎn)單,我們只需要把以上兩步都去掉除盏,在自定義類型處理類的注解@javaType和@MappedJdbcTypes都移除叉橱,配置文件中把 typehandler 屬性配置移除,直接在映射文件中編寫:
<resultMap id="MyResultMap" type="com.panshenlian.pojo.User">
<!-- id為int類型者蠕,但是沒指定自定義類型處理器窃祝,不受影響-->
<id column="id" property="id" />
<!-- username為String類型,但是沒指定自定義類型處理器踱侣,不受影響-->
<id column="username" property="username" />
<!-- password為String類型粪小,但是沒指定自定義類型處理器,不受影響-->
<id column="password" property="password" />
<!-- birthday為String類型抡句,指定自定義類型處理器探膊,受影響!-->
<id column="birthday" property="birthday" typeHandler="com.panshenlian.typeHandler.MyStringHandler"/>
</resultMap>
<select id="findAll" resultType="com.panshenlian.pojo.User" resultMap="MyResultMap">
select * from User
</select>
User 實(shí)體參考:
package com.panshenlian.pojo;
/**
* @Author: panshenlian
* @Description: 用戶實(shí)體
* @Date: Create in 2:08 2020/12/07
*/
public class User {
private int id;
private String username;
private String password;
private String birthday;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
}
最終自定義類型處理器待榔,只會(huì)對(duì) birthday 字段產(chǎn)生影響逞壁,其余字段均不受影響。
自定義類型處理器很靈活究抓,只有當(dāng)指定對(duì)應(yīng)的 Java 類型和 Jdbc 類型時(shí)猾担,處理器才會(huì)具體生效袭灯,否則 Mybatis 會(huì)默認(rèn)匹配系統(tǒng)內(nèi)置的類型處理器刺下。
另外,當(dāng)我們自定義很多類型處理器時(shí)稽荧,系統(tǒng)支持配置包掃描的方式查找類型處理器:
<!-- mybatis-config.xml -->
<typeHandlers>
<package name="org.mybatis.example"/>
</typeHandlers>
注意在使用自動(dòng)發(fā)現(xiàn)功能的時(shí)候橘茉,只能通過注解方式來指定 JDBC 的類型工腋。
你可以創(chuàng)建能夠處理多個(gè)類的泛型類型處理器。為了使用泛型類型處理器畅卓, 需要增加一個(gè)接受該類的 class 作為參數(shù)的構(gòu)造器擅腰,這樣 MyBatis 會(huì)在構(gòu)造一個(gè)類型處理器實(shí)例的時(shí)候傳入一個(gè)具體的類。
//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {
private Class<E> type;
public GenericTypeHandler(Class<E> type) {
if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
this.type = type;
}
...
處理枚舉類型
若想映射枚舉類型 Enum
翁潘,則需要從 EnumTypeHandler
或者 EnumOrdinalTypeHandler
中選擇一個(gè)來使用趁冈。
比如說我們想存儲(chǔ)取近似值時(shí)用到的舍入模式。默認(rèn)情況下拜马,MyBatis 會(huì)利用 EnumTypeHandler
來把 Enum
值轉(zhuǎn)換成對(duì)應(yīng)的名字渗勘。
注意
EnumTypeHandler
在某種意義上來說是比較特別的,其它的處理器只針對(duì)某個(gè)特定的類俩莽,而它不同旺坠,它會(huì)處理任意繼承了Enum
的類。不過扮超,我們可能不想存儲(chǔ)名字取刃,相反我們的 DBA 會(huì)堅(jiān)持使用整形值代碼。那也一樣簡(jiǎn)單:在配置文件中把
EnumOrdinalTypeHandler
加到typeHandlers
中即可出刷, 這樣每個(gè)RoundingMode
將通過他們的序數(shù)值來映射成對(duì)應(yīng)的整形數(shù)值璧疗。
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>
但要是你想在一個(gè)地方將 Enum
映射成字符串,在另外一個(gè)地方映射成整形值呢馁龟?
自動(dòng)映射器(auto-mapper)會(huì)自動(dòng)地選用 EnumOrdinalTypeHandler
來處理枚舉類型病毡, 所以如果我們想用普通的 EnumTypeHandler
,就必須要顯式地為那些 SQL 語(yǔ)句設(shè)置要使用的類型處理器屁柏。
下一篇文章我們才開始介紹映射器 mapper.xml 文件啦膜,如果你首次閱讀映射器概念,可能需要先跳過這里先去了解 mapper.xml 文件配置淌喻,再回頭過來看僧家。
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode"/>
</resultMap>
<select id="getUser" resultMap="usermap">
select * from users
</select>
<insert id="insert">
insert into users (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode}
)
</insert>
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>
<select id="getUser2" resultMap="usermap2">
select * from users2
</select>
<insert id="insert2">
insert into users2 (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
)
</insert>
</mapper>
注意,這里的 select 語(yǔ)句強(qiáng)制使用 resultMap
來代替 resultType
裸删。
5八拱、objectFactory(對(duì)象工廠)
每次 MyBatis 創(chuàng)建結(jié)果對(duì)象的新實(shí)例時(shí),它都會(huì)使用一個(gè)對(duì)象工廠(ObjectFactory)實(shí)例來完成實(shí)例化工作涯塔。 默認(rèn)的對(duì)象工廠需要做的僅僅是實(shí)例化目標(biāo)類肌稻,要么通過默認(rèn)無(wú)參構(gòu)造方法,要么通過存在的參數(shù)映射來調(diào)用帶有參數(shù)的構(gòu)造方法匕荸。 如果想覆蓋對(duì)象工廠的默認(rèn)行為爹谭,可以通過創(chuàng)建自己的對(duì)象工廠來實(shí)現(xiàn)。比如:
// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
public Object create(Class type) {
return super.create(type);
}
public Object create(Class type, List constructorArgTypes, List constructorArgs) {
return super.create(type, constructorArgTypes, constructorArgs);
}
public void setProperties(Properties properties) {
super.setProperties(properties);
}
public boolean isCollection(Class type) {
return Collection.class.isAssignableFrom(type);
}
}
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory>
ObjectFactory 接口很簡(jiǎn)單榛搔,它包含兩個(gè)創(chuàng)建用的方法诺凡,一個(gè)是處理默認(rèn)構(gòu)造方法的东揣,另外一個(gè)是處理帶參數(shù)的構(gòu)造方法的。 最后腹泌,setProperties 方法可以被用來配置 ObjectFactory嘶卧,在初始化你的 ObjectFactory 實(shí)例后, objectFactory 元素體中定義的屬性會(huì)被傳遞給 setProperties 方法凉袱。
正常情況下我們不需要使用到芥吟,或者說不建議使用,除非業(yè)務(wù)上確實(shí)需要對(duì)一個(gè)特殊實(shí)體初始構(gòu)造做一個(gè)默認(rèn)屬性值配置等處理专甩,其余情況不推薦使用运沦,避免產(chǎn)生不可控風(fēng)險(xiǎn)。
6配深、plugins(插件)
MyBatis 允許你在映射語(yǔ)句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用携添。默認(rèn)情況下,MyBatis 允許使用插件來攔截的方法調(diào)用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
插件功能主要開放攔截的對(duì)象就是以上列舉的 Mybatis 四大組件篓叶,后續(xù)我們講 Mybatis 核心API 的時(shí)候或者單獨(dú)介紹自定義插件的時(shí)候會(huì)詳細(xì)說明烈掠,這里大家可以先大致了解,包括數(shù)據(jù)分頁(yè)缸托、操作日志增強(qiáng)左敌、sql 性能監(jiān)控等都可以通過插件實(shí)現(xiàn),不過會(huì)存儲(chǔ)改造的風(fēng)險(xiǎn)俐镐,畢竟這些都是核心的 API 矫限。
這四大類中方法具體可以通過查看每個(gè)方法的簽名來發(fā)現(xiàn),或者直接查看 MyBatis 發(fā)行包中的源代碼佩抹。 如果你想做的不僅僅是監(jiān)控方法的調(diào)用叼风,那么你最好相當(dāng)了解要重寫的方法的行為。 因?yàn)樵谠噲D修改或重寫已有方法的行為時(shí)棍苹,很可能會(huì)破壞 MyBatis 的核心模塊无宿。 這些都是更底層的類和方法,所以使用插件的時(shí)候要特別當(dāng)心枢里。
通過 MyBatis 提供的強(qiáng)大機(jī)制孽鸡,使用插件是非常簡(jiǎn)單的,只需實(shí)現(xiàn) Interceptor 接口栏豺,并指定想要攔截的類彬碱,方法,參數(shù)(由于有多態(tài)的情況)即可奥洼。
// ExamplePlugin.java
@Intercepts({
@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
private Properties properties = new Properties();
public Object intercept(Invocation invocation) throws Throwable {
// implement pre processing if need
Object returnObject = invocation.proceed();
// implement post processing if need
return returnObject;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
上面的插件將會(huì)攔截在 Executor 實(shí)例中所有的 “update” 方法調(diào)用巷疼, 這里的 Executor 是負(fù)責(zé)執(zhí)行底層映射語(yǔ)句的內(nèi)部對(duì)象。
覆蓋配置類 「 謹(jǐn)慎使用溉卓,存在風(fēng)險(xiǎn) 」
除了用插件來修改 MyBatis 核心行為以外皮迟,還可以通過完全覆蓋配置類來達(dá)到目的。只需繼承配置類后覆蓋其中的某個(gè)方法桑寨,再把它傳遞到 SqlSessionFactoryBuilder.build(myConfig) 方法即可伏尼。再次重申,這可能會(huì)極大影響 MyBatis 的行為尉尾,務(wù)請(qǐng)慎之又慎爆阶。
7、environments(環(huán)境配置)
MyBatis 可以配置成適應(yīng)多種環(huán)境沙咏,這種機(jī)制有助于將 SQL 映射應(yīng)用于多種數(shù)據(jù)庫(kù)之中辨图, 現(xiàn)實(shí)情況下有多種理由需要這么做。例如肢藐,開發(fā)故河、測(cè)試和生產(chǎn)環(huán)境需要有不同的配置;或者想在具有相同 Schema 的多個(gè)生產(chǎn)數(shù)據(jù)庫(kù)中使用相同的 SQL 映射吆豹。還有許多類似的使用場(chǎng)景鱼的。
不過要記住:盡管可以配置多個(gè)環(huán)境痘煤,但每個(gè) SqlSessionFactory 實(shí)例只能選擇一種環(huán)境凑阶。
所以,如果你想連接兩個(gè)數(shù)據(jù)庫(kù)衷快,就需要?jiǎng)?chuàng)建兩個(gè) SqlSessionFactory 實(shí)例宙橱,每個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)一個(gè)。而如果是三個(gè)數(shù)據(jù)庫(kù)蘸拔,就需要三個(gè)實(shí)例师郑,依此類推,記起來很簡(jiǎn)單:
每個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)一個(gè) SqlSessionFactory 實(shí)例调窍。
為了指定創(chuàng)建哪種環(huán)境呕乎,只要將它作為可選的參數(shù)傳遞給 SqlSessionFactoryBuilder 即可≡删В可以接受環(huán)境配置的兩個(gè)方法簽名是:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果忽略了環(huán)境參數(shù)猬仁,那么將會(huì)加載默認(rèn)環(huán)境,如下所示:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
environments 元素定義了如何配置環(huán)境先誉。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
注意一些關(guān)鍵點(diǎn):
- 默認(rèn)使用的環(huán)境 ID(比如:default="development")湿刽。
- 每個(gè) environment 元素定義的環(huán)境 ID(比如:id="development")。
- 事務(wù)管理器的配置(比如:type="JDBC")褐耳。
- 數(shù)據(jù)源的配置(比如:type="POOLED")诈闺。
默認(rèn)環(huán)境和環(huán)境 ID 顧名思義。 環(huán)境可以隨意命名铃芦,但務(wù)必保證默認(rèn)的環(huán)境 ID 要匹配其中一個(gè)環(huán)境 ID雅镊。
事務(wù)管理器(transactionManager)
在 MyBatis 中有兩種類型的事務(wù)管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 這個(gè)配置直接使用了 JDBC 的提交和回滾設(shè)施襟雷,它依賴從數(shù)據(jù)源獲得的連接來管理事務(wù)作用域。
- MANAGED – 這個(gè)配置幾乎沒做什么仁烹。它從不提交或回滾一個(gè)連接耸弄,而是讓容器來管理事務(wù)的整個(gè)生命周期(比如 JEE 應(yīng)用服務(wù)器的上下文)。 默認(rèn)情況下它會(huì)關(guān)閉連接卓缰。然而一些容器并不希望連接被關(guān)閉计呈,因此需要將 closeConnection 屬性設(shè)置為 false 來阻止默認(rèn)的關(guān)閉行為。例如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
如果你正在使用 Spring + MyBatis征唬,則沒有必要配置事務(wù)管理器捌显,因?yàn)?Spring 模塊會(huì)使用自帶的管理器來覆蓋前面的配置。這兩種事務(wù)管理器類型都不需要設(shè)置任何屬性总寒。它們其實(shí)是類型別名扶歪,換句話說,你可以用 TransactionFactory 接口實(shí)現(xiàn)類的全限定名或類型別名代替它們摄闸。
public interface TransactionFactory {
default void setProperties(Properties props) { // 從 3.5.2 開始击罪,該方法為默認(rèn)方法
// 空實(shí)現(xiàn)
}
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
在事務(wù)管理器實(shí)例化后,所有在 XML 中配置的屬性將會(huì)被傳遞給 setProperties() 方法贪薪。你的實(shí)現(xiàn)還需要?jiǎng)?chuàng)建一個(gè) Transaction 接口的實(shí)現(xiàn)類媳禁,這個(gè)接口也很簡(jiǎn)單:
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}
使用這兩個(gè)接口,你可以完全自定義 MyBatis 對(duì)事務(wù)的處理画切。
數(shù)據(jù)源(dataSource)
dataSource 元素使用標(biāo)準(zhǔn)的 JDBC 數(shù)據(jù)源接口來配置 JDBC 連接對(duì)象的資源竣稽。
大多數(shù) MyBatis 應(yīng)用程序會(huì)按示例中的例子來配置數(shù)據(jù)源。雖然數(shù)據(jù)源配置是可選的霍弹,但如果要啟用延遲加載特性毫别,就必須配置數(shù)據(jù)源。
有三種內(nèi)建的數(shù)據(jù)源類型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
UNPOOLED– 這個(gè)數(shù)據(jù)源的實(shí)現(xiàn)會(huì)每次請(qǐng)求時(shí)打開和關(guān)閉連接典格。雖然有點(diǎn)慢岛宦,但對(duì)那些數(shù)據(jù)庫(kù)連接可用性要求不高的簡(jiǎn)單應(yīng)用程序來說,是一個(gè)很好的選擇耍缴。 性能表現(xiàn)則依賴于使用的數(shù)據(jù)庫(kù)砾肺,對(duì)某些數(shù)據(jù)庫(kù)來說,使用連接池并不重要防嗡,這個(gè)配置就很適合這種情形变汪。UNPOOLED 類型的數(shù)據(jù)源僅僅需要配置以下 5 種屬性:
-
driver
– 這是 JDBC 驅(qū)動(dòng)的 Java 類全限定名(并不是 JDBC 驅(qū)動(dòng)中可能包含的數(shù)據(jù)源類)。 -
url
– 這是數(shù)據(jù)庫(kù)的 JDBC URL 地址蚁趁。 -
username
– 登錄數(shù)據(jù)庫(kù)的用戶名裙盾。 -
password
– 登錄數(shù)據(jù)庫(kù)的密碼。 -
defaultTransactionIsolationLevel
– 默認(rèn)的連接事務(wù)隔離級(jí)別。 -
defaultNetworkTimeout
– 等待數(shù)據(jù)庫(kù)操作完成的默認(rèn)網(wǎng)絡(luò)超時(shí)時(shí)間(單位:毫秒)番官。查看java.sql.Connection#setNetworkTimeout()
的 API 文檔以獲取更多信息庐完。
作為可選項(xiàng),你也可以傳遞屬性給數(shù)據(jù)庫(kù)驅(qū)動(dòng)徘熔。只需在屬性名加上“driver.”前綴即可门躯,例如:
driver.encoding=UTF8
這將通過 DriverManager.getConnection(url, driverProperties) 方法傳遞值為
UTF8
的encoding
屬性給數(shù)據(jù)庫(kù)驅(qū)動(dòng)。
POOLED– 這種數(shù)據(jù)源的實(shí)現(xiàn)利用“池”的概念將 JDBC 連接對(duì)象組織起來近顷,避免了創(chuàng)建新的連接實(shí)例時(shí)所必需的初始化和認(rèn)證時(shí)間生音。 這種處理方式很流行宁否,能使并發(fā) Web 應(yīng)用快速響應(yīng)請(qǐng)求窒升。
除了上述提到 UNPOOLED 下的屬性外,還有更多屬性用來配置 POOLED 的數(shù)據(jù)源:
-
poolMaximumActiveConnections
– 在任意時(shí)間可存在的活動(dòng)(正在使用)連接數(shù)量慕匠,默認(rèn)值:10 -
poolMaximumIdleConnections
– 任意時(shí)間可能存在的空閑連接數(shù)饱须。 -
poolMaximumCheckoutTime
– 在被強(qiáng)制返回之前,池中連接被檢出(checked out)時(shí)間台谊,默認(rèn)值:20000 毫秒(即 20 秒) -
poolTimeToWait
– 這是一個(gè)底層設(shè)置蓉媳,如果獲取連接花費(fèi)了相當(dāng)長(zhǎng)的時(shí)間,連接池會(huì)打印狀態(tài)日志并重新嘗試獲取一個(gè)連接(避免在誤配置的情況下一直失敗且不打印日志)锅铅,默認(rèn)值:20000 毫秒(即 20 秒)酪呻。 -
poolMaximumLocalBadConnectionTolerance
– 這是一個(gè)關(guān)于壞連接容忍度的底層設(shè)置, 作用于每一個(gè)嘗試從緩存池獲取連接的線程盐须。 如果這個(gè)線程獲取到的是一個(gè)壞的連接玩荠,那么這個(gè)數(shù)據(jù)源允許這個(gè)線程嘗試重新獲取一個(gè)新的連接,但是這個(gè)重新嘗試的次數(shù)不應(yīng)該超過poolMaximumIdleConnections
與poolMaximumLocalBadConnectionTolerance
之和贼邓。 默認(rèn)值:3(新增于 3.4.5) -
poolPingQuery
– 發(fā)送到數(shù)據(jù)庫(kù)的偵測(cè)查詢阶冈,用來檢驗(yàn)連接是否正常工作并準(zhǔn)備接受請(qǐng)求。默認(rèn)是“NO PING QUERY SET”塑径,這會(huì)導(dǎo)致多數(shù)數(shù)據(jù)庫(kù)驅(qū)動(dòng)出錯(cuò)時(shí)返回恰當(dāng)?shù)腻e(cuò)誤消息女坑。 -
poolPingEnabled
– 是否啟用偵測(cè)查詢。若開啟统舀,需要設(shè)置poolPingQuery
屬性為一個(gè)可執(zhí)行的 SQL 語(yǔ)句(最好是一個(gè)速度非炒移快的 SQL 語(yǔ)句),默認(rèn)值:false誉简。 -
poolPingConnectionsNotUsedFor
– 配置 poolPingQuery 的頻率绰筛。可以被設(shè)置為和數(shù)據(jù)庫(kù)連接超時(shí)時(shí)間一樣描融,來避免不必要的偵測(cè)铝噩,默認(rèn)值:0(即所有連接每一時(shí)刻都被偵測(cè) — 當(dāng)然僅當(dāng) poolPingEnabled 為 true 時(shí)適用)。
JNDI – 這個(gè)數(shù)據(jù)源實(shí)現(xiàn)是為了能在如 EJB 或應(yīng)用服務(wù)器這類容器中使用,容器可以集中或在外部配置數(shù)據(jù)源骏庸,然后放置一個(gè) JNDI 上下文的數(shù)據(jù)源引用毛甲。這種數(shù)據(jù)源配置只需要兩個(gè)屬性:
-
initial_context
– 這個(gè)屬性用來在 InitialContext 中尋找上下文(即,initialContext.lookup(initial_context))具被。這是個(gè)可選屬性玻募,如果忽略,那么將會(huì)直接從 InitialContext 中尋找 data_source 屬性一姿。 -
data_source
– 這是引用數(shù)據(jù)源實(shí)例位置的上下文路徑七咧。提供了 initial_context 配置時(shí)會(huì)在其返回的上下文中進(jìn)行查找,沒有提供時(shí)則直接在 InitialContext 中查找叮叹。
JNDI 可理解是一種仿 windows 注冊(cè)表形式的數(shù)據(jù)源艾栋。
和其他數(shù)據(jù)源配置類似,可以通過添加前綴“env.”直接把屬性傳遞給 InitialContext蛉顽。比如:
env.encoding=UTF8
這就會(huì)在 InitialContext 實(shí)例化時(shí)往它的構(gòu)造方法傳遞值為 UTF8
的 encoding
屬性蝗砾。
你可以通過實(shí)現(xiàn)接口 org.apache.ibatis.datasource.DataSourceFactory
來使用第三方數(shù)據(jù)源實(shí)現(xiàn):
public interface DataSourceFactory {
void setProperties(Properties props);
DataSource getDataSource();
}
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
可被用作父類來構(gòu)建新的數(shù)據(jù)源適配器,比如下面這段插入 C3P0 數(shù)據(jù)源所必需的代碼:
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
public C3P0DataSourceFactory() {
this.dataSource = new ComboPooledDataSource();
}
}
為了令其工作携冤,記得在配置文件中為每個(gè)希望 MyBatis 調(diào)用的 setter 方法增加對(duì)應(yīng)的屬性悼粮。 下面是一個(gè)可以連接至 PostgreSQL 數(shù)據(jù)庫(kù)的例子:
<dataSource type="org.myproject.C3P0DataSourceFactory">
<property name="driver" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql:mydb"/>
<property name="username" value="postgres"/>
<property name="password" value="root"/>
</dataSource>
8、databaseIdProvider(數(shù)據(jù)庫(kù)廠商標(biāo)識(shí))
MyBatis 可以根據(jù)不同的數(shù)據(jù)庫(kù)廠商執(zhí)行不同的語(yǔ)句曾棕,這種多廠商的支持是基于映射語(yǔ)句中的 databaseId
屬性扣猫。 MyBatis 會(huì)加載帶有匹配當(dāng)前數(shù)據(jù)庫(kù) databaseId
屬性和所有不帶 databaseId
屬性的語(yǔ)句。 如果同時(shí)找到帶有 databaseId
和不帶 databaseId
的相同語(yǔ)句翘地,則后者會(huì)被舍棄申尤。 為支持多廠商特性,只要像下面這樣在 mybatis-config.xml 文件中加入 databaseIdProvider
即可:
<databaseIdProvider type="DB_VENDOR" />
databaseIdProvider 對(duì)應(yīng)的 DB_VENDOR 實(shí)現(xiàn)會(huì)將 databaseId 設(shè)置為 DatabaseMetaData#getDatabaseProductName()
返回的字符串子眶。 由于通常情況下這些字符串都非常長(zhǎng)瀑凝,而且相同產(chǎn)品的不同版本會(huì)返回不同的值,你可能想通過設(shè)置屬性別名來使其變短:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
在提供了屬性別名時(shí)臭杰,databaseIdProvider 的 DB_VENDOR 實(shí)現(xiàn)會(huì)將 databaseId 設(shè)置為數(shù)據(jù)庫(kù)產(chǎn)品名與屬性中的名稱第一個(gè)相匹配的值粤咪,如果沒有匹配的屬性槽卫,將會(huì)設(shè)置為 “null”被去。 在這個(gè)例子中申鱼,如果 getDatabaseProductName()
返回“Oracle (DataDirect)”黎比,databaseId 將被設(shè)置為“oracle”。
你可以通過實(shí)現(xiàn)接口 org.apache.ibatis.mapping.DatabaseIdProvider
并在 mybatis-config.xml 中注冊(cè)來構(gòu)建自己的 DatabaseIdProvider:
public interface DatabaseIdProvider {
default void setProperties(Properties p) { // 從 3.5.2 開始温兼,該方法為默認(rèn)方法
// 空實(shí)現(xiàn)
}
String getDatabaseId(DataSource dataSource) throws SQLException;
}
9俱恶、mappers(映射器)
既然 MyBatis 的行為已經(jīng)由上述元素配置完了究孕,我們現(xiàn)在就要來定義 SQL 映射語(yǔ)句了比搭。 但首先冠跷,我們需要告訴 MyBatis 到哪里去找到這些語(yǔ)句。 在自動(dòng)查找資源方面,Java 并沒有提供一個(gè)很好的解決方案蜜托,所以最好的辦法是直接告訴 MyBatis 到哪里去找映射文件抄囚。 你可以使用相對(duì)于類路徑的資源引用,或完全限定資源定位符(包括 file:///
形式的 URL)橄务,或類名和包名等幔托。例如:
<!-- 使用相對(duì)于類路徑的資源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定資源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口實(shí)現(xiàn)類的完全限定類名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 將包內(nèi)的映射器接口實(shí)現(xiàn)全部注冊(cè)為映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
XML 映射文件
在 XML 核心配置文件介紹中,我們介紹了映射文件 mapper.xml 的引入蜂挪。
對(duì)于 Mapper 具體的映射配置文件重挑,是 Mybatis 最復(fù)雜、最核心的組件棠涮,其中的標(biāo)簽內(nèi)容體系也是特別詳實(shí)谬哀,包括它的參數(shù)類型、動(dòng)態(tài)SQL故爵、定義SQL玻粪、緩存信息等等隅津,我們?cè)谙乱黄恼轮性龠M(jìn)行梳理討論诬垂,這里我們簡(jiǎn)單引出。
總結(jié)
原本我計(jì)劃把核心配置文件和映射器 mapper 文件放一塊講伦仍,但是發(fā)現(xiàn)內(nèi)容太多太多了结窘,基本核心配置文件就已經(jīng)講得有點(diǎn)拖堂了,雖然這幾大頂級(jí)標(biāo)簽使用起來已經(jīng)毫不費(fèi)力充蓝。SQL 映射器配置文件,我們后續(xù)更新谓苟,這塊基本是和我們?nèi)粘4蚪坏雷罡哳l的操作官脓。
本篇完,本系列下一篇我們講《 Mybatis系列全解(五):全網(wǎng)最全涝焙!詳解Mybatis的Mapper映射文件 》卑笨。
BIU ~ 文章持續(xù)更新,微信搜索「潘潘和他的朋友們」第一時(shí)間閱讀仑撞,隨時(shí)有驚喜赤兴。本文會(huì)在 GitHub https://github.com/JavaWorld 收錄,熱騰騰的技術(shù)隧哮、框架桶良、面經(jīng)、解決方案沮翔,我們都會(huì)以最美的姿勢(shì)第一時(shí)間送達(dá)陨帆,歡迎 Star。