MyBatis 是一款優(yōu)秀的持久層框架沪编,它支持定制化 SQL呼盆、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集蚁廓。
在本篇文章中访圃,會講到如下內(nèi)容:
MyBatis 概念
MyBatis 優(yōu)缺點(diǎn)
MyBatis 緩存
MyBatis 儲存
MyBatis 映射
常見 MyBatis 面試題
適合人群: 正在學(xué)習(xí) Java 開發(fā)和準(zhǔn)備面試的 Java 程序員朋友們。
由于篇幅有限相嵌,這邊只展示部分面試題腿时,有需要完整版和更多相關(guān)Java知識點(diǎn)、面試題的朋友可以加q群:1103806531? 備注:簡書? ?免費(fèi)領(lǐng)取~
1. 最佳實踐中饭宾,通常一個Xml映射文件批糟,都會寫一個Dao接口與之對應(yīng),請問捏雌,這個Dao接口的工作原理是什么跃赚?Dao接口里的方法,參數(shù)不同時,方法能重載嗎纬傲?
答:Dao接口满败,就是人們常說的Mapper接口,接口的全限名叹括,就是映射文件中的namespace的值算墨,接口的方法名,就是映射文件中MappedStatement的id值汁雷,接口方法內(nèi)的參數(shù)净嘀,就是傳遞給sql的參數(shù)。Mapper接口是沒有實現(xiàn)類的侠讯,當(dāng)調(diào)用接口方法時挖藏,接口全限名+方法名拼接字符串作為key值,可唯一定位一個MappedStatement厢漩,舉例:com.mybatis3.mappers.StudentDao.findStudentById膜眠,可以唯一找到namespace為com.mybatis3.mappers.StudentDao下面id =的findStudentById的MappedStatement。在Mybatis中溜嗜,每一個<select>宵膨、<insert>、<update>炸宵、<delete>標(biāo)簽辟躏,都會被解析為一個MappedStatement對象。
Dao接口里的方法土全,是不能重載的捎琐,因為是全限名+方法名的保存和尋找策略。
Dao接口的工作原理是JDK動態(tài)代理涯曲,Mybatis運(yùn)行時會使用JDK動態(tài)代理為Dao接口生成代理proxy對象野哭,代理對象proxy會攔截接口方法,轉(zhuǎn)而執(zhí)行MappedStatement所代表的sql幻件,然后將sql執(zhí)行結(jié)果返回拨黔。
2、Mybatis是如何進(jìn)行分頁的绰沥?分頁插件的原理是什么篱蝇?
答:Mybatis使用RowBounds對象進(jìn)行分頁,它是針對ResultSet結(jié)果集執(zhí)行的內(nèi)存分頁徽曲,而非物理分頁零截,可以在sql內(nèi)直接書寫帶有物理分頁的參數(shù)來完成物理分頁功能,也可以使用分頁插件來完成物理分頁秃臣。
分頁插件的基本原理是使用Mybatis提供的插件接口涧衙,實現(xiàn)自定義插件哪工,在插件的攔截方法內(nèi)攔截待執(zhí)行的sql,然后重寫sql弧哎,根據(jù)dialect方言雁比,添加對應(yīng)的物理分頁語句和物理分頁參數(shù)。
舉例:select * from student撤嫩,攔截sql后重寫為:select t.* from (select * from student)t limit 0偎捎,10
3、簡述Mybatis的插件運(yùn)行原理序攘,以及如何編寫一個插件茴她。
答:Mybatis僅可以編寫針對ParameterHandler、ResultSetHandler程奠、StatementHandler丈牢、Executor這4種接口的插件,Mybatis使用JDK的動態(tài)代理瞄沙,為需要攔截的接口生成代理對象以實現(xiàn)接口方法攔截功能赡麦,每當(dāng)執(zhí)行這4種接口對象的方法時,就會進(jìn)入攔截方法帕识,具體就是InvocationHandler的invoke()方法,當(dāng)然遂铡,只會攔截那些你指定需要攔截的方法肮疗。
實現(xiàn)Mybatis的Interceptor接口并復(fù)寫intercept()方法,然后再給插件編寫注解扒接,指定要攔截哪一個接口的哪些方法即可伪货,記住,別忘了在配置文件中配置你編寫的插件钾怔。
4碱呼、Mybatis執(zhí)行批量插入,能返回數(shù)據(jù)庫主鍵列表嗎宗侦?
答:能愚臀,JDBC都能,Mybatis當(dāng)然也能矾利。
5姑裂、Mybatis動態(tài)sql是做什么的?都有哪些動態(tài)sql男旗?能簡述一下動態(tài)sql的執(zhí)行原理不舶斧?
答:Mybatis動態(tài)sql可以讓我們在Xml映射文件內(nèi),以標(biāo)簽的形式編寫動態(tài)sql察皇,完成邏輯判斷和動態(tài)拼接sql的功能茴厉,Mybatis提供了9種動態(tài)sql標(biāo)簽trim|where|set|foreach|if|choose|when|otherwise|bind。
其執(zhí)行原理為,使用OGNL從sql參數(shù)對象中計算表達(dá)式的值矾缓,根據(jù)表達(dá)式的值動態(tài)拼接sql怀酷,以此來完成動態(tài)sql的功能。
6而账、Mybatis是如何將sql執(zhí)行結(jié)果封裝為目標(biāo)對象并返回的胰坟?都有哪些映射形式?
答:第一種是使用<resultMap>標(biāo)簽泞辐,逐一定義列名和對象屬性名之間的映射關(guān)系笔横。第二種是使用sql列的別名功能,將列別名書寫為對象屬性名咐吼,比如T_NAME AS NAME吹缔,對象屬性名一般是name,小寫锯茄,但是列名不區(qū)分大小寫厢塘,Mybatis會忽略列名大小寫,只能找到與之對應(yīng)對象屬性名肌幽,你甚至可以寫成T_NAME AS NaMe晚碾,Mybatis一樣可以正常工作。
有了列名與屬性名的映射關(guān)系后喂急,Mybatis通過反射創(chuàng)建對象格嘁,同時使用反射給對象的屬性逐一賦值并返回,那些找不到映射關(guān)系的屬性廊移,是無法完成賦值的糕簿。
7、Mybatis能執(zhí)行一對一狡孔、一對多的關(guān)聯(lián)查詢嗎懂诗?都有哪些實現(xiàn)方式,以及它們之間的區(qū)別苗膝。
答:能殃恒,Mybatis不僅可以執(zhí)行一對一、一對多的關(guān)聯(lián)查詢辱揭,還可以執(zhí)行多對一芋类,多對多的關(guān)聯(lián)查詢,多對一查詢界阁,其實就是一對一查詢侯繁,只需要把selectOne()修改為selectList()即可;多對多查詢泡躯,其實就是一對多查詢贮竟,只需要把selectOne()修改為selectList()即可丽焊。
關(guān)聯(lián)對象查詢,有兩種實現(xiàn)方式咕别,一種是單獨(dú)發(fā)送一個sql去查詢關(guān)聯(lián)對象技健,賦給主對象,然后返回主對象惰拱。另一種是使用嵌套查詢雌贱,嵌套查詢的含義為使用join查詢,一部分列是A對象的屬性值偿短,另外一部分列是關(guān)聯(lián)對象B的屬性值欣孤,好處是只發(fā)一個sql查詢,就可以把主對象和其關(guān)聯(lián)對象查出來昔逗。
那么問題來了降传,join查詢出來100條記錄,如何確定主對象是5個勾怒,而不是100個婆排?其去重復(fù)的原理是<resultMap>標(biāo)簽內(nèi)的<id>子標(biāo)簽,指定了唯一確定一條記錄的id列笔链,Mybatis根據(jù)<id>列值來完成100條記錄的去重復(fù)功能段只,<id>可以有多個,代表了聯(lián)合主鍵的語意鉴扫。
同樣主對象的關(guān)聯(lián)對象翼悴,也是根據(jù)這個原理去重復(fù)的,盡管一般情況下幔妨,只有主對象會有重復(fù)記錄,關(guān)聯(lián)對象一般不會重復(fù)谍椅。
8误堡、Mybatis是否支持延遲加載?如果支持雏吭,它的實現(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)方法時孝治,進(jìn)入攔截器方法列粪,比如調(diào)用a.getB().getName()审磁,攔截器invoke()方法發(fā)現(xiàn)a.getB()是null值,那么就會單獨(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,支持延遲加載的原理都是一樣的氯质。
9募舟、Mybatis的Xml映射文件中,不同的Xml映射文件闻察,id是否可以重復(fù)拱礁?
答:不同的Xml映射文件,如果配置了namespace辕漂,那么id可以重復(fù)呢灶;如果沒有配置namespace,那么id不能重復(fù)钉嘹;畢竟namespace不是必須的鸯乃,只是最佳實踐而已。
原因就是namespace+id是作為Map<String, MappedStatement>的key使用的跋涣,如果沒有namespace缨睡,就剩下id,那么陈辱,id重復(fù)會導(dǎo)致數(shù)據(jù)互相覆蓋奖年。有了namespace,自然id就可以重復(fù)沛贪,namespace不同陋守,namespace+id自然也就不同。
10利赋、Mybatis中如何執(zhí)行批處理水评?
答:使用BatchExecutor完成批處理。
11媚送、Mybatis都有哪些Executor執(zhí)行器中燥?它們之間的區(qū)別是什么?
答:Mybatis有三種基本的Executor執(zhí)行器塘偎,SimpleExecutor褪那、ReuseExecutor幽纷、BatchExecutor。
SimpleExecutor:每執(zhí)行一次update或select博敬,就開啟一個Statement對象友浸,用完立刻關(guān)閉Statement對象。
ReuseExecutor:執(zhí)行update或select偏窝,以sql作為key查找Statement對象收恢,存在就使用,不存在就創(chuàng)建祭往,用完后伦意,不關(guān)閉Statement對象,而是放置于Map內(nèi)硼补,供下一次使用驮肉。簡言之,就是重復(fù)使用Statement對象已骇。
BatchExecutor:執(zhí)行update(沒有select离钝,JDBC批處理不支持select),將所有sql都添加到批處理中(addBatch())褪储,等待統(tǒng)一執(zhí)行(executeBatch())卵渴,它緩存了多個Statement對象,每個Statement對象都是addBatch()完畢后鲤竹,等待逐一執(zhí)行executeBatch()批處理浪读。與JDBC批處理相同。
作用范圍:Executor的這些特點(diǎn)辛藻,都嚴(yán)格限制在SqlSession生命周期范圍內(nèi)碘橘。
12、Mybatis中如何指定使用哪一種Executor執(zhí)行器吱肌?
答:在Mybatis配置文件中痘拆,可以指定默認(rèn)的ExecutorType執(zhí)行器類型,也可以手動給DefaultSqlSessionFactory的創(chuàng)建SqlSession的方法傳遞ExecutorType類型參數(shù)岩榆。
13、Mybatis是否可以映射Enum枚舉類坟瓢?
答:Mybatis可以映射枚舉類勇边,不單可以映射枚舉類,Mybatis可以映射任何對象到表的一列上折联。映射方式為自定義一個TypeHandler粒褒,實現(xiàn)TypeHandler的setParameter()和getResult()接口方法。TypeHandler有兩個作用诚镰,一是完成從javaType至jdbcType的轉(zhuǎn)換奕坟,二是完成jdbcType至javaType的轉(zhuǎn)換祥款,體現(xiàn)為setParameter()和getResult()兩個方法,分別代表設(shè)置sql問號占位符參數(shù)和獲取列查詢結(jié)果月杉。
14刃跛、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)簽尚未解析到,尚不存在泥彤,此時欲芹,Mybatis會將A標(biāo)簽標(biāo)記為未解析狀態(tài),然后繼續(xù)解析余下的標(biāo)簽吟吝,包含B標(biāo)簽菱父,待所有標(biāo)簽解析完畢,Mybatis會重新解析那些被標(biāo)記為未解析的標(biāo)簽剑逃,此時再解析A標(biāo)簽時浙宜,B標(biāo)簽已經(jīng)存在,A標(biāo)簽也就可以正常解析完成了蛹磺。
15粟瞬、簡述Mybatis的Xml映射文件和Mybatis內(nèi)部數(shù)據(jù)結(jié)構(gòu)之間的映射關(guān)系?
答:Mybatis將所有Xml配置信息都封裝到All-In-One重量級對象Configuration內(nèi)部萤捆。在Xml映射文件中裙品,<parameterMap>標(biāo)簽會被解析為ParameterMap對象,其每個子元素會被解析為ParameterMapping對象俗或。<resultMap>標(biāo)簽會被解析為ResultMap對象市怎,其每個子元素會被解析為ResultMapping對象。每一個<select>辛慰、<insert>区匠、<update>、<delete>標(biāo)簽均會被解析為MappedStatement對象帅腌,標(biāo)簽內(nèi)的sql會被解析為BoundSql對象驰弄。
最后
希望這篇文章對大家有幫助麻汰!
我這邊也整理了一份 架構(gòu)師全套視頻教程 和關(guān)于java的系統(tǒng)化資料,包括java核心知識點(diǎn)戚篙、面試專題和20年最新的互聯(lián)網(wǎng)真題五鲫、電子書等都有。
有需要的朋友可以加q群:1103806531? 備注:簡書? ?免費(fèi)領(lǐng)取~