第二章SQL映射文件
XML 映射文件:MyBatis 的真正強(qiáng)大在于它的映射語句,這是它的魔力所在。由于它的異常強(qiáng)大,映射器的,XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進(jìn)行對比,你會立即發(fā)現(xiàn)省掉了將近95% 的代碼。MyBatis 為聚焦于 SQL 而構(gòu)建,以盡可能地為你減少麻煩。SQL 映射文件只有很少的幾個頂級元素(按照應(yīng)被定義的順序列出):
cache– 對給定命名空間的緩存配置。
cache-ref– 對其他命名空間緩存配置的引用。
resultMap– 是最復(fù)雜也是最強(qiáng)大的元素,用來描述如何從數(shù)據(jù)庫結(jié)果集中來加載對象。? parameterMap ?? – 已被廢棄!老式風(fēng)格的參數(shù)映射。更好的辦法是使用內(nèi)聯(lián)參數(shù),此元素可能在將來被移除。文檔中不會介紹此元素。
sql– 可被其他語句引用的可重用語句塊。
insert– 映射插入語句
update– 映射更新語句
delete– 映射刪除語句
select– 映射查詢語句
1.使用select完成單條件查詢:查詢語句是 MyBatis 中最常用的元素之一,光能把數(shù)據(jù)存到數(shù)據(jù)庫中價值并不大,只有還能重新取出來才有用,多數(shù)應(yīng)用也都是查詢比修改要頻繁。對每個插入、更新或刪除操作,通常間隔多個查詢操作。這是 MyBatis 的基本原則之一,也是將焦點(diǎn)和努力放在查詢和結(jié)果映射的原因。簡單查詢的 select 元素是非常簡單的。比如:

這個語句被稱作 selectPerson,接受一個 int(或 Integer)類型的參數(shù),并返回一個? HashMap 類型的對象,其中的鍵是列名,值便是結(jié)果行中的對應(yīng)值。注意參數(shù)符號:

這就告訴 MyBatis 創(chuàng)建一個預(yù)處理語句(PreparedStatement)參數(shù),在 JDBC 中,這樣的一個參數(shù)在 SQL 中會由一個“?”來標(biāo)識,并被傳遞到一個新的預(yù)處理語句中,就像這樣:

當(dāng)然,使用 JDBC 意味著需要更多的代碼來提取結(jié)果并將它們映射到對象實例中,而這就是 MyBatis 節(jié)省你時間的地方。參數(shù)和結(jié)果映射還有更深入的細(xì)節(jié)。這些細(xì)節(jié)會分別在后面單獨(dú)的小節(jié)中呈現(xiàn)。 select 元素允許你配置很多屬性來配置每條語句的作用細(xì)節(jié)。上面我們只是通過一個條件進(jìn)行查詢操作,但是在實際應(yīng)用中數(shù)據(jù)查詢會有多種條件,結(jié)果也會有各種類型

(2)insert, update 和 delete? 數(shù)據(jù)變更語句 insert,update 和 delete 的實現(xiàn)非常接近:只需要修改一小部分代碼:

插入語句的配置規(guī)則更加豐富,在插入語句里面有一些額外的屬性和子元素用來處理主鍵的生成,而且有多種生成方式。如果你的數(shù)據(jù)庫還支持多行插入, 你也可以傳入一個 Author 數(shù)組或集合,并返回自動生成的主鍵。對于不支持自動生成類型的數(shù)據(jù)庫或可能不支持自動生成主鍵的 JDBC 驅(qū)動,MyBatis 有另外一種方法來生成主鍵。這里有一個簡單(甚至很傻)的示例,它可以生成一個隨機(jī) ID(你最好不要這么做,但這里展示了MyBatis 處理問題的靈活性及其所關(guān)心的廣度)

字符串替換:默認(rèn)情況下,使用#{}格式的語法會導(dǎo)致 MyBatis 創(chuàng)建PreparedStatement參數(shù)占位符并安全地設(shè)置參數(shù)(就像使用 ? 一樣)這樣做更安全,更迅速,通常也是首選做法,不過有時你就是想直接在 SQL 語句中插入一個不轉(zhuǎn)義的字符串? 比如,像 ORDER BY,你可以這樣來使用:

這里 MyBatis 不會修改或轉(zhuǎn)義字符串。當(dāng) SQL 語句中的元數(shù)據(jù)(如表名或列名)是動態(tài)生成的時候,字符串替換將會非常有用 舉個例子,如果你想通過任何一列從表中select數(shù)據(jù)時,不需要像下面這樣寫:

2.使用resultMap完成查詢結(jié)果的展示:resultMap 元素是 MyBatis 中最重要最強(qiáng)大的元素。它可以讓你從 90% 的 JDBC ResultSets 數(shù)據(jù)提取代碼中解放出來,并在一些情形下允許你進(jìn)行一些JDBC 不支持的操作。實際上,在為一些比如連接的復(fù)雜語句編寫映射代碼的時候,一份 resultMap 能夠代替實現(xiàn)同等功能的長達(dá)數(shù)千行的代碼。ResultMap的設(shè)計思想是,對于簡單的語句根本不需要配置顯式的結(jié)果映射,而對于復(fù)雜一點(diǎn)的語句只需要描述它們的關(guān)系就行了。
resultMap是Mybatis最強(qiáng)大的元素,它可以將查詢到的復(fù)雜數(shù)據(jù)(比如查詢到幾個表中數(shù)據(jù))映射到一個結(jié)果集當(dāng)中。resultMap包含的元素:

如果collection標(biāo)簽是使用嵌套查詢,格式如下:

以下以實例介紹resultMap的用法:一、簡單需求:一個商品的結(jié)果映射;
1、創(chuàng)建商品pojo對象:

對應(yīng)的resultMap:

二、商品pojo類添加屬性集合:一個商品會有一些屬性,現(xiàn)在需要將查詢出的商品屬性添加到商品對象中,首先需要在原商品pojo類的基礎(chǔ)上中添加屬性的集合:

將Collection標(biāo)簽添加到resultMap中,這里有兩種方式:
1、嵌套結(jié)果 ,對應(yīng)的resultMap:

查詢語句:

2、關(guān)聯(lián)的嵌套查詢(在collection中添加select屬性):
商品結(jié)果集映射resultMap

collection的select會執(zhí)行下面的查詢屬性語句:

?屬性結(jié)果集映射:

BasePlusResultMap包含了屬性查詢語句的Collection所以通過下面的查詢商品語句就可獲得商品以及其包含的屬性集合:

3.Mybatis的緩存
1??什么是查詢緩存:mybatis提供查詢緩存,用于減輕數(shù)據(jù)壓力,提高數(shù)據(jù)庫性能。
mybaits提供一級緩存,和二級緩存。
一級緩存是SqlSession級別的緩存。在操作數(shù)據(jù)庫時需要構(gòu)造 sqlSession對象,在對象中有一個(內(nèi)存區(qū)域)數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。
一級緩存的作用域是同一個SqlSession,在同一個sqlSession中兩次執(zhí)行相同的sql語句,第一次執(zhí)行完畢會將數(shù)據(jù)庫中查詢的數(shù)據(jù)寫到緩存(內(nèi)存),第二次會從緩存中獲取數(shù)據(jù)將不再從數(shù)據(jù)庫查詢,從而提高查詢效率。當(dāng)一個sqlSession結(jié)束后該sqlSession中的一級緩存也就不存在了。Mybatis默認(rèn)開啟一級緩存。
二級緩存是mapper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession去操作數(shù)據(jù)庫得到數(shù)據(jù)會存在二級緩存區(qū)域,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。
二級緩存是多個SqlSession共享的,其作用域是mapper的同一個namespace,不同的sqlSession兩次執(zhí)行相同namespace下的sql語句且向sql中傳遞參數(shù)也相同即最終執(zhí)行相同的sql語句,第一次執(zhí)行完畢會將數(shù)據(jù)庫中查詢的數(shù)據(jù)寫到緩存(內(nèi)存),第二次會從緩存中獲取數(shù)據(jù)將不再從數(shù)據(jù)庫查詢,從而提高查詢效率。Mybatis默認(rèn)沒有開啟二級緩存需要在setting全局參數(shù)中配置開啟二級緩存。如果緩存中有數(shù)據(jù)就不用從數(shù)據(jù)庫中獲取,大大提高系統(tǒng)性能。
1????一級緩存工作原理:第一次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數(shù)據(jù)庫查詢用戶信息。得到用戶信息,將用戶信息存儲到一級緩存中。如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。第二次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
2????一級緩存測試
mybatis默認(rèn)支持一級緩存,不需要在配置文件去配置。按照上邊一級緩存原理步驟去測試。
@Test
public?voidtestCache1()throwsException{
? ? ? ? ? ? SqlSessionsqlSession =?sqlSessionFactory.openSession();//創(chuàng)建代理對象
UserMapperuserMapper = sqlSession.getMapper(UserMapper.class);
? //下邊查詢使用一個SqlSession
? //第一次發(fā)起請求,查詢id為1的用戶
? Useruser1 = userMapper.findUserById(1);
? ? System.out.println(user1);
//????如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。
?//更新user1的信息
? ?? user1.setUsername('測試用戶22');
? ? ? userMapper.updateUser(user1);
?//執(zhí)行commit操作去清空緩存
? ? ? ? sqlSession.commit();
//第二次發(fā)起請求,查詢id為1的用戶
? ? ?? Useruser2 = userMapper.findUserById(1);
? ? ? ? ? ?? System.out.println(user2);
? ? ? ? ? ? ? sqlSession.close();
?? }
3.useCache配置禁用二級緩存:在statement中設(shè)置useCache=false可以禁用當(dāng)前select語句的二級緩存,即每次查詢都會發(fā)出sql去查詢,默認(rèn)情況是true,即該sql使用二級緩存。
<selectid='findOrderListResultMap' resultMap='ordersUserMap'?useCache='false'>
總結(jié):針對每次查詢都需要最新的數(shù)據(jù)sql,要設(shè)置成useCache=false,禁用二級緩存。
4.mybatis刷新緩存(就是清空緩存)在mapper的同一個namespace中,如果有其它insert、update、delete操作數(shù)據(jù)后需要刷新緩存,如果不執(zhí)行刷新緩存會出現(xiàn)臟讀。 設(shè)置statement配置中的flushCache='true'?屬性,默認(rèn)情況下為true即刷新緩存,如果改成false則不會刷新。使用緩存時如果手動修改數(shù)據(jù)庫表中的查詢數(shù)據(jù)會出現(xiàn)臟讀。如下:

總結(jié):一般下執(zhí)行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存默認(rèn)情況下為true,我們不用去設(shè)置它,這樣可以避免數(shù)據(jù)庫臟讀。
5.二級應(yīng)用場景:對于訪問多的查詢請求且用戶對查詢結(jié)果實時性要求不高,此時可采用mybatis二級緩存技術(shù)降低數(shù)據(jù)庫訪問量,提高訪問速度,業(yè)務(wù)場景比如:耗時較高的統(tǒng)計分析sql、電話賬單查詢sql等。
實現(xiàn)方法如下:通過設(shè)置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據(jù)數(shù)據(jù)變化頻率設(shè)置緩存刷新間隔flushInterval,比如設(shè)置為30分鐘、60分鐘、24小時等,根據(jù)需求而定。
6.二級緩存局限性: ?? mybatis二級緩存對細(xì)粒度的數(shù)據(jù)級別的緩存實現(xiàn)不好,對同時緩存較多條數(shù)據(jù)的緩存,比如如下需求:對商品信息進(jìn)行緩存,由于商品信息查詢訪問量大,但是要求用戶每次都能查詢最新的商品信息,此時如果使用mybatis的二級緩存就無法實現(xiàn)當(dāng)一個商品變化時只刷新該商品的緩存信息而不刷新其它商品的信息,因為mybaits的二級緩存區(qū)域以mapper為單位劃分,當(dāng)一個商品信息變化會將所有商品信息的緩存數(shù)據(jù)全部清空。解決此類問題需要在業(yè)務(wù)層根據(jù)需求對數(shù)據(jù)有針對性緩存。需要使用三級緩存
以上就是Mybatis? Sql 映射文件的簡單介紹和使用