Mybatis知識及運(yùn)用(IDER)續(xù)作二

第二章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ù)時,不需要像下面這樣寫:

提示: 用這種方式接受用戶的輸入,并將其用于語句中的參數(shù)是不安全的,會導(dǎo)致潛在的 SQL 注入攻擊,因此要么不允許用戶輸入這些字段,要么自行轉(zhuǎn)義并檢驗。

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)簽是使用嵌套查詢,格式如下:

注意:<collection>標(biāo)簽中的column:要傳遞給select查詢語句的參數(shù),如果傳遞多個參數(shù),格式為column= ” {參數(shù)名1=表字段1,參數(shù)名2=表字段2} ; ?

以下以實例介紹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 映射文件的簡單介紹和使用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容