MyBatis

1. #{}和${}的區(qū)別是什么?

{} 是 Properties 文件中的變量占位符钻心,它可以用于標(biāo)簽屬性值和 sql 內(nèi)部脱茉,屬于靜態(tài)文本替換搁进,比如{driver}會(huì)被靜態(tài)替換為 com.mysql.jdbc.Driver 姿染。

{} 是 sql 的參數(shù)占位符蹄皱,Mybatis 會(huì)將 sql 中的 #{} 替換為?號旧噪,在 sql 執(zhí)行前會(huì)使用 PreparedStatement 的參數(shù)設(shè)置方法芹扭,按序給 sql 的?號占位符設(shè)置參數(shù)值麻顶,比如 ps.setInt(0, parameterValue)赦抖, #{item.name} 的取值方式為使用反射從參數(shù)對象中獲取 item 對象的 name 屬性值,相當(dāng)于 param.getItem().getName() 辅肾。

2. Xml 映射文件中队萤,除了常?的 select|insert|updae|delete 標(biāo) 簽之外,還有哪些標(biāo)簽?

還有很多其他的標(biāo)簽矫钓,<resultMap> 要尔、 <parameterMap> 、 <sql> 新娜、 <include> 赵辕、 <selectKey> ,加上動(dòng)態(tài) sql 的 9 個(gè)標(biāo)簽概龄, trim|where|set|foreach|if|choose|when|otherwise|bind 等还惠,其中為 sql 片段標(biāo)簽,通過<include> 標(biāo)簽引入 sql 片段私杜, <selectKey> 為不支持自增的主鍵生成策略標(biāo)簽蚕键。

3. 最佳實(shí)踐中,通常一個(gè) Xml 映射文件歪今,都會(huì)寫一個(gè) Dao 接口 與之對應(yīng)嚎幸,請問,這個(gè) Dao 接口的工作原理是什么?Dao 接口里的 方法寄猩,參數(shù)不同時(shí)嫉晶,方法能重載嗎?

Dao 接口,就是人們常說的 Mapper 接口田篇,接口的全限名替废,就是映射文件中的 namespace 的值,接口的方法名泊柬,就是映射文件中 MappedStatement 的 id 值椎镣,接口方法內(nèi)的參數(shù),就是傳遞 給 sql 的參數(shù)兽赁。 Mapper 接口是沒有實(shí)現(xiàn)類的状答,當(dāng)調(diào)用接口方法時(shí),接口全限名+方法名拼接字符 串作為 key 值刀崖,可唯一定位一個(gè) MappedStatement 惊科,舉例: com.mybatis3.mappers.StudentDao.findStudentById ,可以唯一找到 namespace為 com.mybatis3.mappers.StudentDao 下面 id = findStudentById 的 MappedStatement 亮钦。在 Mybatis 中馆截,每一個(gè) <select> 、 <insert> 、 <update> 蜡娶、 <delete> 標(biāo)簽混卵,都會(huì)被解析為一個(gè) MappedStatement 對象。

Dao 接口里的方法窖张,是不能重載的幕随,因?yàn)槭侨廾?方法名的保存和尋找策略。

Dao 接口的工作原理是 JDK 動(dòng)態(tài)代理宿接,Mybatis 運(yùn)行時(shí)會(huì)使用 JDK 動(dòng)態(tài)代理為 Dao 接口生成代 理 proxy 對象合陵,代理對象 proxy 會(huì)攔截接口方法,轉(zhuǎn)而執(zhí)行 MappedStatement 所代表的 sql澄阳,然后 將 sql 執(zhí)行結(jié)果返回拥知。

4. Mybatis 是如何進(jìn)行分?的?分?插件的原理是什么?

Mybatis 使用 RowBounds 對象進(jìn)行分?,它是針對 ResultSet 結(jié)果集執(zhí)行的內(nèi)存分?碎赢,而 非物理分?低剔,可以在 sql 內(nèi)直接書寫帶有物理分?的參數(shù)來完成物理分?功能,也可以使用分? 插件來完成物理分?肮塞。

分?插件的基本原理是使用 Mybatis 提供的插件接口襟齿,實(shí)現(xiàn)自定義插件,在插件的攔截方法內(nèi)攔 截待執(zhí)行的 sql枕赵,然后重寫 sql猜欺,根據(jù) dialect 方言,添加對應(yīng)的物理分?語句和物理分?參數(shù)拷窜。

5. 簡述 Mybatis 的插件運(yùn)行原理开皿,以及如何編寫一個(gè)插件。

Mybatis 僅可以編寫針對ParameterHandler 篮昧、 ResultSetHandler赋荆、StatementHandler 、 Executor 這 4 種接口的插件懊昨,

Mybatis 使用 JDK 的動(dòng)態(tài)代理窄潭,為需要攔截的接口生成代理對象以實(shí)現(xiàn)接口方法攔截功能,每當(dāng) 執(zhí)行這 4 種接口對象的方法時(shí)酵颁,就會(huì)進(jìn)入攔截方法嫉你,具體就是 InvocationHandler 的 invoke() 方法,當(dāng)然躏惋,只會(huì)攔截那些你指定需要攔截的方法幽污。

實(shí)現(xiàn) Mybatis 的 Interceptor 接口并復(fù)寫 intercept() 方法,然后在給插件編寫注解其掂,指定要攔截哪 一個(gè)接口的哪些方法即可油挥,記住潦蝇,別忘了在配置文件中配置你編寫的插件款熬。

6. Mybatis 執(zhí)行批量插入深寥,能返回?cái)?shù)據(jù)庫主鍵列表嗎?

能,JDBC 都能贤牛,Mybatis 當(dāng)然也能惋鹅。

7. Mybatis 動(dòng)態(tài) sql 是做什么的?都有哪些動(dòng)態(tài) sql?能簡述一 下動(dòng)態(tài) sql 的執(zhí)行原理不?

Mybatis 動(dòng)態(tài) sql 可以讓我們在 Xml 映射文件內(nèi),以標(biāo)簽的形式編寫動(dòng)態(tài) sql殉簸,完成邏輯判斷 和動(dòng)態(tài)拼接 sql 的功能闰集,Mybatis 提供了 9 種動(dòng)態(tài) sql 標(biāo)簽
trim|where|set|foreach|if|choose|when|otherwise|bind 。

其執(zhí)行原理為般卑,使用 OGNL 從 sql 參數(shù)對象中計(jì)算表達(dá)式的值武鲁,根據(jù)表達(dá)式的值動(dòng)態(tài)拼接 sql,以此來完成動(dòng)態(tài) sql 的功能蝠检。

8. Mybatis 是如何將 sql 執(zhí)行結(jié)果封裝為目標(biāo)對象并返回的?都有哪些映射形式?

第一種是使用 <resultMap> 標(biāo)簽沐鼠,逐一定義列名和對象屬性名之間的映射關(guān)系。第二種是使 用 sql 列的別名功能叹谁,將列別名書寫為對象屬性名饲梭,比如 T_NAME AS NAME,對象屬性名一般 是 name焰檩,小寫憔涉,但是列名不區(qū)分大小寫,Mybatis 會(huì)忽略列名大小寫析苫,智能找到與之對應(yīng)對象 屬性名兜叨,你甚至可以寫成 T_NAME AS NaMe,Mybatis 一樣可以正常工作衩侥。

有了列名與屬性名的映射關(guān)系后浪腐,Mybatis 通過反射創(chuàng)建對象,同時(shí)使用反射給對象的屬性逐一 賦值并返回顿乒,那些找不到映射關(guān)系的屬性议街,是無法完成賦值的。

9. Mybatis 能執(zhí)行一對一璧榄、一對多的關(guān)聯(lián)查詢嗎?都有哪些實(shí)現(xiàn) 方式特漩,以及它們之間的區(qū)別。

能骨杂,Mybatis 不僅可以執(zhí)行一對一涂身、一對多的關(guān)聯(lián)查詢,還可以執(zhí)行多對一搓蚪,多對多的關(guān)聯(lián) 查詢蛤售,多對一查詢,其實(shí)就是一對一查詢,只需要把 selectOne() 修改為 selectList() 即可;多對 多查詢悴能,其實(shí)就是一對多查詢揣钦,只需要把 selectOne() 修改為 selectList() 即可。

關(guān)聯(lián)對象查詢漠酿,有兩種實(shí)現(xiàn)方式冯凹,一種是單獨(dú)發(fā)送一個(gè) sql 去查詢關(guān)聯(lián)對象,賦給主對象炒嘲,然后 返回主對象宇姚。另一種是使用嵌套查詢,嵌套查詢的含義為使用 join 查詢夫凸,一部分列是 A 對象的屬 性值浑劳,另外一部分列是關(guān)聯(lián)對象 B 的屬性值,好處是只發(fā)一個(gè) sql 查詢夭拌,就可以把主對象和其關(guān) 聯(lián)對象查出來呀洲。

那么問題來了,join 查詢出來 100 條記錄啼止,如何確定主對象是 5 個(gè)道逗,而不是 100 個(gè)?其去重復(fù)的 原理是 <resultMap> 標(biāo)簽內(nèi)的 <id> 子標(biāo)簽,指定了唯一確定一條記錄的 id 列献烦,Mybatis 根據(jù)列 值來完成 100 條記錄的去重復(fù)功能滓窍, <id> 可以有多個(gè),代表了聯(lián)合主鍵的語意巩那。

同樣主對象的關(guān)聯(lián)對象吏夯,也是根據(jù)這個(gè)原理去重復(fù)的,盡管一般情況下即横,只有主對象會(huì)有重復(fù)記 錄噪生,關(guān)聯(lián)對象一般不會(huì)重復(fù)。

舉例:下面 join 查詢出來 6 條記錄东囚,一跺嗽、二列是 Teacher 對象列,第三列為 Student 對象列页藻, Mybatis 去重復(fù)處理后桨嫁,結(jié)果為 1 個(gè)老師 6 個(gè)學(xué)生,而不是 6 個(gè)老師 6 個(gè)學(xué)生份帐。


image.png

10. Mybatis 是否支持延遲加載?如果支持璃吧,它的實(shí)現(xiàn)原理是什么?

Mybatis 僅支持 association 關(guān)聯(lián)對象和 collection 關(guān)聯(lián)集合對象的延遲加載,association 指 的就是一對一废境,collection 指的就是一對多查詢畜挨。在 Mybatis 配置文件中筒繁,可以配置是否啟用延 遲加載 lazyLoadingEnabled=true|false

它的原理是,使用 CGLIB 創(chuàng)建目標(biāo)對象的代理對象巴元,當(dāng)調(diào)用目標(biāo)方法時(shí)毡咏,進(jìn)入攔截器方法,比 如調(diào)用 a.getB().getName() 务冕,攔截器 invoke() 方法發(fā)現(xiàn) a.getB() 是 null 值,那么就會(huì)單獨(dú)發(fā)送事 先保存好的查詢關(guān)聯(lián) B 對象的 sql幻赚,把 B 查詢上來禀忆,然后調(diào)用 a.setB(b),于是 a 的對象 b 屬性 就有值了落恼,接著完成 a.getB().getName() 方法的調(diào)用箩退。這就是延遲加載的基本原理。

當(dāng)然了佳谦,不光是 Mybatis戴涝,幾乎所有的包括 Hibernate,支持延遲加載的原理都是一樣的钻蔑。

11. Mybatis 的 Xml 映射文件中啥刻,不同的 Xml 映射文件,id 是 否可以重復(fù)?

不同的 Xml 映射文件咪笑,如果配置了 namespace可帽,那么 id 可以重復(fù);如果沒有配置 namespace,那么 id 不能重復(fù);畢竟 namespace 不是必須的窗怒,只是最佳實(shí)踐而已映跟。

原因就是 namespace+id 是作為 Map<String, MappedStatement> 的 key 使用的,如果沒有 namespace扬虚,就剩下 id努隙,那么,id 重復(fù)會(huì)導(dǎo)致數(shù)據(jù)互相覆蓋辜昵。有了 namespace荸镊,自然 id 就可以 重復(fù),namespace 不同堪置,namespace+id 自然也就不同贷洲。

12. Mybatis 中如何執(zhí)行批處理?

使用 BatchExecutor 完成批處理。

13. Mybatis 都有哪些 Executor 執(zhí)行器?它們之間的區(qū)別是什么?

Mybatis 有三種基本的 Executor 執(zhí)行
器晋柱, SimpleExecutor 优构、 ReuseExecutor 、 BatchExecutor 雁竞。

SimpleExecutor :每執(zhí)行一次 update 或 select钦椭,就開啟一個(gè) Statement 對象拧额,用完立刻關(guān)閉 Statement 對象。

`ReuseExecutor :執(zhí)行 update 或 select彪腔,以 sql 作為 key 查找 Statement 對象侥锦,存在就使用, 不存在就創(chuàng)建德挣,用完后恭垦,不關(guān)閉 Statement 對象,而是放置于 Map<String, Statement>內(nèi)格嗅,供下 一次使用番挺。簡言之,就是重復(fù)使用 Statement 對象屯掖。

BatchExecutor :執(zhí)行 update(沒有 select玄柏,JDBC 批處理不支持 select),將所有 sql 都添加 到批處理中(addBatch())贴铜,等待統(tǒng)一執(zhí)行(executeBatch())粪摘,它緩存了多個(gè) Statement 對 象,每個(gè) Statement 對象都是 addBatch()完畢后绍坝,等待逐一執(zhí)行 executeBatch()批處理徘意。與 JDBC 批處理相同。

作用范圍:Executor 的這些特點(diǎn)轩褐,都嚴(yán)格限制在 SqlSession 生命周期范圍內(nèi)映砖。

14. Mybatis 中如何指定使用哪一種 Executor 執(zhí)行器?

在 Mybatis 配置文件中,可以指定默認(rèn)的 ExecutorType 執(zhí)行器類型灾挨,也可以手動(dòng)給
DefaultSqlSessionFactory 的創(chuàng)建 SqlSession 的方法傳遞 ExecutorType 類型參數(shù)邑退。

15. Mybatis 是否可以映射 Enum 枚舉類?

Mybatis 可以映射枚舉類,不單可以映射枚舉類劳澄,Mybatis 可以映射任何對象到表的一列 上地技。映射方式為自定義一個(gè) TypeHandler ,實(shí)現(xiàn) TypeHandler 的 setParameter() 和 getResult() 接口方法秒拔。 TypeHandler 有兩個(gè)作用莫矗,一是完成從 javaType 至 jdbcType 的轉(zhuǎn)換,二是完成 jdbcType 至 javaType 的轉(zhuǎn)換砂缩,體現(xiàn)為 setParameter() 和 getResult() 兩個(gè)方法作谚,分別代表設(shè)置 sql 問號占位符參數(shù)和獲取列查詢結(jié)果。

16. Mybatis 映射文件中庵芭,如果 A 標(biāo)簽通過 include 引用了 B 標(biāo) 簽的內(nèi)容妹懒,請問,B 標(biāo)簽?zāi)芊穸x在 A 標(biāo)簽的后面双吆,還是說必須定 義在 A 標(biāo)簽的前面?

雖然 Mybatis 解析 Xml 映射文件是按照順序解析的眨唬,但是会前,被引用的 B 標(biāo)簽依然可以定義 在任何地方,Mybatis 都可以正確識別匾竿。

原理是瓦宜,Mybatis 解析 A 標(biāo)簽,發(fā)現(xiàn) A 標(biāo)簽引用了 B 標(biāo)簽岭妖,但是 B 標(biāo)簽尚未解析到临庇,尚不存 在,此時(shí)昵慌,Mybatis 會(huì)將 A 標(biāo)簽標(biāo)記為未解析狀態(tài)假夺,然后繼續(xù)解析余下的標(biāo)簽,包含 B 標(biāo)簽废离,待 所有標(biāo)簽解析完畢侄泽,Mybatis 會(huì)重新解析那些被標(biāo)記為未解析的標(biāo)簽礁芦,此時(shí)再解析 A 標(biāo)簽時(shí)蜻韭,B 標(biāo)簽已經(jīng)存在,A 標(biāo)簽也就可以正常解析完成了柿扣。

17. 簡述 Mybatis 的 Xml 映射文件和 Mybatis 內(nèi)部數(shù)據(jù)結(jié)構(gòu)之 間的映射關(guān)系?

Mybatis 將所有 Xml 配置信息都封裝到 All-In-One 重量級對象 Configuration 內(nèi)部肖方。在 Xml 映射文件中, <parameterMap> 標(biāo)簽會(huì)被解析為 ParameterMap 對象未状,其每個(gè)子元素會(huì)被解析為 ParameterMapping 對象俯画。 <resultMap> 標(biāo)簽會(huì)被解析為 ResultMap 對象,其每個(gè)子元素會(huì)被解 析為 ResultMapping 對象司草。每一個(gè) <select>??<insert>??<update>??<delete> 標(biāo)簽均會(huì)被解析為
MappedStatement 對象艰垂,標(biāo)簽內(nèi)的 sql 會(huì)被解析為 BoundSql 對象。

18. 為什么說 Mybatis 是半自動(dòng) ORM 映射工具?它與全自動(dòng)的 區(qū)別在哪里?

Hibernate 屬于全自動(dòng) ORM 映射工具埋虹,使用 Hibernate 查詢關(guān)聯(lián)對象或者關(guān)聯(lián)集合對象時(shí)猜憎, 可以根據(jù)對象關(guān)系模型直接獲取,所以它是全自動(dòng)的搔课。而 Mybatis 在查詢關(guān)聯(lián)對象或關(guān)聯(lián)集合對 象時(shí)胰柑,需要手動(dòng)編寫 sql 來完成,所以爬泥,稱之為半自動(dòng) ORM 映射工具柬讨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市袍啡,隨后出現(xiàn)的幾起案子踩官,更是在濱河造成了極大的恐慌,老刑警劉巖境输,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卖鲤,死亡現(xiàn)場離奇詭異肾扰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蛋逾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門集晚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人区匣,你說我怎么就攤上這事偷拔。” “怎么了亏钩?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵莲绰,是天一觀的道長。 經(jīng)常有香客問我姑丑,道長蛤签,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任栅哀,我火速辦了婚禮震肮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘留拾。我一直安慰自己戳晌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布痴柔。 她就那樣靜靜地躺著沦偎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咳蔚。 梳的紋絲不亂的頭發(fā)上豪嚎,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機(jī)與錄音谈火,去河邊找鬼侈询。 笑死,一個(gè)胖子當(dāng)著我的面吹牛堆巧,可吹牛的內(nèi)容都是我干的妄荔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谍肤,長吁一口氣:“原來是場噩夢啊……” “哼啦租!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荒揣,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤篷角,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后系任,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恳蹲,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虐块,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嘉蕾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贺奠。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖错忱,靈堂內(nèi)的尸體忽然破棺而出儡率,到底是詐尸還是另有隱情,我是刑警寧澤以清,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布儿普,位于F島的核電站,受9級特大地震影響掷倔,放射性物質(zhì)發(fā)生泄漏眉孩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一勒葱、第九天 我趴在偏房一處隱蔽的房頂上張望浪汪。 院中可真熱鬧,春花似錦错森、人聲如沸吟宦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至袁波,卻和暖如春瓦阐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背篷牌。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工睡蟋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枷颊。 一個(gè)月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓戳杀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親夭苗。 傳聞我的和親對象是個(gè)殘疾皇子信卡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容