《深入淺出MyBatis技術(shù)原理與實(shí)戰(zhàn)》2016年版本 讀書筆記
第一章 MyBatis簡(jiǎn)介
1.ORM模型:對(duì)象關(guān)系映射,即數(shù)據(jù)庫(kù)表與對(duì)象之間的映射關(guān)系模型衰猛。
2.Hibernate缺點(diǎn):全表映射,sql不靈活萍聊,性能略差弊予。
3.MyBatis需要提供的映射文件:
- SQL
- 映射規(guī)則
- POJO
4.MyBatis相比于Hibernate更為靈活、可以動(dòng)態(tài)生成映射關(guān)系楼肪。
第二章 MyBatis入門
1.核心組件:
- SqlSessionFactoryBuilder:讀取配置到Configuration然后生成SqlSessionFactory培廓。
- SqlSessionFactory:工廠模式生成SqlSession。默認(rèn)實(shí)現(xiàn)類DefaultSqlSessionFactory春叫。
- SqlSession:獲取Mapper接口肩钠。
- SQL Mapper:由Java接口和XML文件構(gòu)成,負(fù)責(zé)發(fā)送SQL執(zhí)行并返回結(jié)果暂殖。
2.生命周期:
- SqlSessionFactoryBuilder:方法局部价匠,創(chuàng)建完即可銷毀。
- SqlSessionFactory:存活于MyBatis應(yīng)用的整個(gè)生命周期呛每,宜采用單例踩窖,減少開銷。
- SqlSession:相當(dāng)于JDBC中的Connection晨横,存活于應(yīng)用的請(qǐng)求和操作洋腮。
- SQL Mapper:接口類箫柳,盡量在一個(gè)SqlSession事務(wù)中使用。
3.實(shí)例詳見:https://github.com/conanswp/MyBatisDemo.git
第三章 配置
一.MyBatis配置XML層次結(jié)構(gòu)啥供,各標(biāo)簽需要順序使用悯恍。
1.properties用于配置屬性,可以使用property配置子元素或者使用resource屬性引用配置文件伙狐。
2.如果需要加密涮毫,可以使用上面配置密文,而在程序使用SqlSessionFactoryBuild構(gòu)建SqlSessionFactory的build方法時(shí)傳入解密后的properties文件贷屎。
3.配置優(yōu)先級(jí):使用程序構(gòu)建時(shí)傳入的參數(shù)>配置文件>xml中properties中定義的子元素窒百。
二.setting用于配置改變mybatis的行為,例如指定日志組件等豫尽。
<settings>
<setting name="logImpl" value="LOG4J" />
</settings>
三.typeAliases用于定義別名篙梢,不區(qū)分大小寫,用于在mybatis上下文中使用美旧。
1.系統(tǒng)已定義別名:_byte->byte,byte->Byte渤滞,map->Map,collection->Collection榴嗅,iterator->Iterator妄呕,resultSet->ResultSet等。
2.還可以使用typeAliases定義掃描包嗽测,然后在類中使用@Alias注解定義別名绪励。
四.typeHandler類型處理器:用于轉(zhuǎn)換javaType和jdbcType。
1.系統(tǒng)已經(jīng)定義的typeHandler:例如Boolean對(duì)應(yīng)于BooleanTypeHandler唠粥,SqlTimestampTypeHandler處理時(shí)間精確到秒的時(shí)間疏魏。
2.通過指定jdbcType,javaType晤愧,handler屬性大莫,可以自定義typeHandler。
3.枚舉類型typeHandler:可以用于實(shí)現(xiàn)字典官份。
3.1EnumTypeHander:使用枚舉字符串名稱作為參數(shù)傳遞只厘。
3.2EnumOrdinalTypeHandler:使用整數(shù)下標(biāo)作為參數(shù)傳遞,默認(rèn)枚舉類新處理器舅巷。
五.ObjectFactory是mybatis默認(rèn)的對(duì)象工廠羔味,可以使用該標(biāo)簽定義新的對(duì)象工廠,要求實(shí)現(xiàn)DefaultObjectFactory钠右。
六.插件用于覆蓋mybatis核心對(duì)象的行為赋元。
七.environments用于配置環(huán)境,如配置多個(gè)數(shù)據(jù)源,配置多個(gè)數(shù)據(jù)庫(kù)事務(wù)们陆。
1.事務(wù)管理器transactionManager:JDBC->JDBC管理事務(wù)寒瓦,MANAGED:容器管理事務(wù)情屹,適用于JNDI數(shù)據(jù)源坪仇,自定義->使用者自定義數(shù)據(jù)庫(kù)事務(wù)管理辦法。
2.數(shù)據(jù)源dataSource:UNPOOLED->非連接池?cái)?shù)據(jù)庫(kù)垃你,POOLED->數(shù)據(jù)庫(kù)連接池椅文,JNDI->JNDI數(shù)據(jù)源,自定義->自定義數(shù)據(jù)源惜颇,如dbcp數(shù)據(jù)源皆刺。
八.databaseIdProvider數(shù)據(jù)庫(kù)廠商標(biāo)識(shí),用于指定sql到對(duì)應(yīng)的數(shù)據(jù)庫(kù)廠商提供的數(shù)據(jù)庫(kù)中運(yùn)行凌摄。即在mapper.xml中的標(biāo)簽中使用databaseId指定數(shù)據(jù)庫(kù)羡蛾。自定義需要實(shí)現(xiàn)DatabaseIdProvider接口。
九.映射器mapper:包括mapper接口和mapper規(guī)則配置锨亏。引入方式:mapper子元素+resouce屬性引入痴怨,包名引入,類名引入等器予。
<mappers>
<mapper resource="com/conanswp/mapper/userMapper.xml" />
</mappers>
第四章 映射器
在映射器中可以定義select查詢浪藻,insert插入,update更新乾翔,delete刪除爱葵,parameterMap參數(shù)映射(已拋棄),sql定義sql,resultMap結(jié)果集反浓,cache/cache-ref命名空間緩存配置等萌丈。
一.select
1.自動(dòng)映射:開在settings中設(shè)置autoMappingBhavior配置自動(dòng)映射策略,其取值為:
- NONE:取消自動(dòng)映射
- PARTIAL:自動(dòng)映射雷则,不映射結(jié)果嵌套的結(jié)果集浓瞪,默認(rèn)值
- FULL:自動(dòng)映射任意復(fù)雜的結(jié)果集,包括嵌套巧婶,性能低
java類中使用駝峰乾颁,數(shù)據(jù)庫(kù)中使用_分隔,可以設(shè)置mapUnderscoreToCamelCase為true實(shí)現(xiàn)自動(dòng)映射艺栈。
2.傳遞多個(gè)參數(shù)可以使用: - map:在傳遞時(shí)根據(jù)map的key來確定英岭。缺點(diǎn)是參數(shù)有業(yè)務(wù)語(yǔ)義,擴(kuò)展維護(hù)困難湿右。
- 使用注解@Param實(shí)現(xiàn)诅妹,然后在select中不使用參數(shù)類型。缺點(diǎn)是參數(shù)多可讀性不高。
- 使用javabean傳遞:parameter指定jababean對(duì)應(yīng)類吭狡。
3.默認(rèn)resultType可以實(shí)現(xiàn)自動(dòng)映射尖殃,resultMap映射結(jié)果集,一般用于復(fù)雜划煮、級(jí)聯(lián)查詢送丰。resultMap中id元素用于標(biāo)識(shí)主鍵,result用于映射數(shù)據(jù)庫(kù)列與對(duì)象屬性弛秋。
二.insert
1.使用keyProperty指定主鍵字段器躏,使用useGeneratedKeys告訴MyBatis這個(gè)主鍵是否使用數(shù)據(jù)庫(kù)內(nèi)置策略生成。
2.可以使用selectKey實(shí)現(xiàn)檢測(cè)是否有數(shù)據(jù)蟹略,沒有插入1登失,有插入當(dāng)前ID+1。
三.update和delete元素執(zhí)行完畢后返回整數(shù)表示影響的記錄條數(shù)挖炬。
四.參數(shù)
1.通過EL可以標(biāo)記參數(shù)的類型揽浙、處理器等,例如:
`
{price,javaType=double,jdbcTye=NUMERIC,numericScale=2}
//表示price屬性處理類型意敛,精度
`
2.支持存儲(chǔ)過程:
- 支持返回IN/OUT/INOUT
- 如果存儲(chǔ)過程返回游標(biāo)jdbcType=CURSOR馅巷,需要可選設(shè)置javaType=ResultSet并定義resultMap
3.對(duì)于返回值是null的,指定StringTypeHandler處理#{note,jdbcType=VARCHAR}
,用jdbcType=VARCHAR提示mybatis使用StringTypeHandler處理null值空闲。
五.可以定義sql元素令杈,然后在select等操作中通過<include refid='x'/>引用。
<sql id='x'>
id,role_name,note
</sql>
<select ...>
select <include refid="x"/> from t_role
</select>
六.resultMap結(jié)果集映射碴倾,現(xiàn)在支持resultMap的查詢逗噩,不支持更新、刪除和修改跌榔。
1.resultMap組成:
- constructor元素用于指定構(gòu)造方法
- id用于表示主鍵异雁,允許多個(gè)主鍵:聯(lián)合主鍵。
- result是POJO到sql列名的映射僧须。
2.可以使用Map存儲(chǔ)結(jié)果集(根據(jù)key讀取結(jié)果)纲刀,但是可讀性較低,一般推薦POJO方式担平。
3.使用POJO存儲(chǔ)結(jié)果集支持自動(dòng)映射示绊,也可以使用resultMap自定義映射。
4.級(jí)聯(lián):
- 一對(duì)一:association
- 一對(duì)多:collection暂论,多對(duì)多可以轉(zhuǎn)化為一對(duì)多
- discriminator:鑒別器面褐,根據(jù)實(shí)際選擇采用哪個(gè)類作為實(shí)例
5.延遲加載:
- 1+N問題:查詢主數(shù)據(jù),是1次查詢取胎,查詢出n條記錄展哭;根據(jù)這n條主記錄湃窍,查詢從記錄,共需要n次匪傍,所以叫數(shù)據(jù)庫(kù)1+n問題您市;這樣會(huì)帶來性能問題,比如役衡,查詢到的n條記錄茵休,我可能只用到其中1條,但是也執(zhí)行了n次從記錄查詢映挂,這是不合理的泽篮。
- mybatis通過設(shè)置全局參數(shù):lazyLoadingEnabled(是否開啟延遲加載功能)和aggressiveLazyLoading(對(duì)任意延遲屬性發(fā)的調(diào)用會(huì)使帶有延遲加載屬性的對(duì)象完整加載盗尸,反之按需加載)解決該問題柑船。由于mybatis延遲加載是按層執(zhí)行的,因此aggressiveLazyLoading設(shè)置為true表示按層加載泼各,false為按需加載鞍时。
- 全局設(shè)置不靈活,可以在association扣蜻、collection和discriminator中使用fetchType="lazy"屬性設(shè)置懶加載(延遲加載)或者fetchType="eager"即時(shí)加載逆巍。
- 延遲加載的實(shí)現(xiàn)原理是通動(dòng)態(tài)代理實(shí)現(xiàn)的。
七.緩存cache
1.默認(rèn)支持一級(jí)緩存:同一個(gè)sqlsession對(duì)象調(diào)用mapper的方法莽使,沒超時(shí)和刷新的情況下只執(zhí)行一次sql锐极。不同的sqlsession還是會(huì)多次發(fā)送sql執(zhí)行。
2.開啟二級(jí)緩存要求POJO是可序列化的(實(shí)現(xiàn)serializable接口)芳肌,然后在配置文件中打開緩存<cache/>灵再。這會(huì)導(dǎo)致:
- select語(yǔ)句會(huì)緩存
- insert/update/delete會(huì)刷新緩存
- 緩存默認(rèn)使用LRU(最近最少使用)算法回收
二級(jí)緩存是sqlsessiofactory級(jí)別共享的。一級(jí)緩存是sqlsession級(jí)別共享的亿笤。
3.二級(jí)緩存屬性: - eviction:緩存策略翎迁,LRU/FIFO/SOFT/WEAK
- flushInterval:刷新時(shí)間
- size:緩存數(shù)目
- readOnly:是否只讀,不能修改
4.支持自定義緩存净薛,例如緩存到redis等汪榔,需要實(shí)現(xiàn)Cache接口。
第五章 動(dòng)態(tài)SQL
支持的動(dòng)態(tài)sql如下:
一.if
常用test合用肃拜,根據(jù)test結(jié)果判斷是否調(diào)用痴腌,如:
select role_no from t_role where 1=1
<if test="roleName!=null and roleName!=''">
and role_name like concat('%',#{roleName},'%')
</if>
二.choose/when/otherwise
實(shí)現(xiàn)switch...case...default邏輯
三.trim/where/set
1.為了避免上面的1=1,可以使用where元素:
<where>
<if test="roleName!=null and roleName!=''">
and role_name like concat('%',#{roleName},'%')
</if>
</where>
2.trim用于去掉and燃领、or等語(yǔ)句士聪。
- prefix:表示語(yǔ)句前綴
- prefixOverrides:需要去掉的字符串
3.set用于更新部分字段而不是全部時(shí)去掉不需要字段后面的逗號(hào)。
四.foreach
遍歷集合柿菩,支持?jǐn)?shù)組戚嗅、List、Set。
五.test
用于條件判斷
六.bind
通過OGNL表達(dá)式自定義一個(gè)上下文變量懦胞。如用于處理模糊搜索時(shí)mysql的使用連接的concat連接,而oracle使用||連接替久。
PS:基本使用學(xué)習(xí)完畢,原理待讀躏尉。