1、什么是 MyBatis?
MyBatis是一個(gè)可以自定義SQL、存儲(chǔ)過(guò)程和高級(jí)映射的持久層框架。
2、講下MyBatis的緩存
MyBatis的緩存分為一級(jí)緩存和二級(jí)緩存,一級(jí)緩存放在session里面,默認(rèn)就有,二級(jí)緩存放在它的命名空間里,默認(rèn)是不打開(kāi)的,使用二級(jí)緩存屬性類需要實(shí)現(xiàn)Serializable序列化接口(可用來(lái)保存對(duì)象的狀態(tài)),可在它的映射文件中配置<cache/>
3、Mybatis是如何進(jìn)行分頁(yè)的?分頁(yè)插件的原理是什么?
Mybatis使用RowBounds對(duì)象進(jìn)行分頁(yè),也可以直接編寫(xiě)sql現(xiàn)分頁(yè), 也可以使用Mybatis的分頁(yè)插件。
分頁(yè)插件的原理:實(shí)現(xiàn)Mybatis提供的接口,實(shí)現(xiàn)自定義插件,在插件的 攔截方法內(nèi)攔截待執(zhí)行的sql,然后重寫(xiě)sql。
舉例:
select * from student
攔截sql后重寫(xiě)為:
select t.* from (select * from student)t limit 0,10
4、簡(jiǎn)述Mybatis的插件運(yùn)行原理,以及如何編寫(xiě)一個(gè)插件?
Mybatis 僅可以編寫(xiě)針對(duì) ParameterHandler、ResultSetHandler、 StatementHandler、Executor 這 4 種接口的插件,Mybatis 通過(guò)動(dòng)態(tài)代
理,為需要攔截的接口生成代理對(duì)象以實(shí)現(xiàn)接口方法攔截功能,每當(dāng)執(zhí)行 這4種接口對(duì)象的方法時(shí),就會(huì)進(jìn)入攔截方法,具體就是 InvocationHandler的invoke。方法,當(dāng)然,只會(huì)攔截那些你指定需要攔截 的方法。實(shí)現(xiàn)Mybatis的Interceptor接口并復(fù)寫(xiě)intercept()方法,然后在給插件 編寫(xiě)注解,指定要攔截哪一個(gè)接口的哪些方法即可,記住,別忘了在配置 文件中配置你編寫(xiě)的插件。
5、Mybatis動(dòng)態(tài)sql是做什么的?都有哪些動(dòng)態(tài)sql?能簡(jiǎn)述一下動(dòng)態(tài)sql 的執(zhí)行原理嗎?
Mybatis動(dòng)態(tài)sql可以讓我們?cè)赬ml映射文件內(nèi),以標(biāo)簽的形式編寫(xiě)動(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|bindo其執(zhí)行原理為,使用OGNL從sql參數(shù)對(duì)象中計(jì)算表達(dá)式的值,根據(jù)表 達(dá)式的值動(dòng)態(tài)拼接sql,以此來(lái)完成動(dòng)態(tài)sql的功能。
6、#{}和${}的區(qū)別是什么?
-
{}是預(yù)編譯處理,${}是字符串替換。
Mybatis在處理#{}時(shí),會(huì)將sql中的#{}替換為?號(hào),調(diào)用 PreparedStatement 的 set 方法來(lái)賦值;
Mybatis在處理
{}替換成變量的值。
使用#{}可以有效的防止SQL注入,提高系統(tǒng)安全性。
7、為什么說(shuō)Mybatis是半自動(dòng)ORM映射工具?它與全自動(dòng)的區(qū)別在哪里?
Hibernate屬于全自動(dòng)ORM映射工具,使用Hibernate查詢關(guān)聯(lián)對(duì)象或者 關(guān)聯(lián)集合對(duì)象時(shí),可以根據(jù)對(duì)象關(guān)系模型直接獲取,所以它是全自動(dòng)的。
Mybatis在查詢關(guān)聯(lián)對(duì)象或關(guān)聯(lián)集合對(duì)象時(shí),需要手動(dòng)編寫(xiě)sql來(lái)完 成,所以,稱之為半自動(dòng)ORM映射工具。
8、Mybatis是否支持延遲加載?如果支持,它的實(shí)現(xiàn)原理是什么?
Mybatis僅支持association關(guān)聯(lián)對(duì)象和collection關(guān)聯(lián)集合對(duì)象的延遲 加載,association指的就是一對(duì)一,collection指的就是一對(duì)多查詢。在 Mybatis配置文件中,可以配置是否啟用延遲加載
lazyLoadingEnabled=true|false 。它的原理是,使用CGLIB創(chuàng)建目標(biāo)對(duì)象的代理對(duì)象,當(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 對(duì)象的sql,把B查詢上來(lái),然后調(diào)用a.setB(b),于是a的對(duì)象b屬 性就有值了,接著完成a.getB().getName()方法的調(diào)用。這就是延遲 加載的基本原理。
9、MyBatis 與 Hibernate 有哪些不同?
Mybatis和hibernate不同,它不完全是一個(gè)ORM框架,因?yàn)镸yBatis 需要程序員自己編寫(xiě)Sql語(yǔ)句,不過(guò)mybatis可以通過(guò)XML或注解方式靈 活配置要運(yùn)行的sql語(yǔ)句,并將java對(duì)象和sql語(yǔ)句映射生成最終執(zhí)行的 sql,最后將sql執(zhí)行的結(jié)果再映射生成java對(duì)象。
Mybatis學(xué)習(xí)門檻低,簡(jiǎn)單易學(xué),程序員直接編寫(xiě)原生態(tài)sql,可嚴(yán)格控 制sql執(zhí)行性能,靈活度高,非常適合對(duì)關(guān)系數(shù)據(jù)模型要求不高的軟件開(kāi) 發(fā),例如互聯(lián)網(wǎng)軟件、企業(yè)運(yùn)營(yíng)類軟件等,因?yàn)檫@類軟件需求變化頻繁, —但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無(wú)法做到數(shù) 據(jù)庫(kù)無(wú)關(guān)性,如果需要實(shí)現(xiàn)支持多種數(shù)據(jù)庫(kù)的軟件則需要自定義多套sql 映射文件,工作量大。
Hibernate對(duì)象/關(guān)系映射能力強(qiáng),數(shù)據(jù)庫(kù)無(wú)關(guān)性好,對(duì)于關(guān)系模型要求 高的軟件(例如需求固定的定制化軟件)如果用hibernate開(kāi)發(fā)可以節(jié)省很多 代碼,提高效率。但是Hibernate的缺點(diǎn)是學(xué)習(xí)門檻高,要精通門檻更 高,而且怎么設(shè)計(jì)O/R映射,在性能和對(duì)象模型之間如何權(quán)衡,以及怎樣 用好Hibernate需要具有很強(qiáng)的經(jīng)驗(yàn)和能力才行??傊?,按照用戶的需求 在有限的資源環(huán)境下只要能做出維護(hù)性、擴(kuò)展性良好的軟件架構(gòu)都是好架 構(gòu),所以框架只有適合才是最好。
10、MyBatis的好處是什么?
MyBatis把sql語(yǔ)句從Java源程序中獨(dú)立出來(lái),放在單獨(dú)的XML文件中 編寫(xiě),給程序的維護(hù)帶來(lái)了很大便利。
MyBatis封裝了底層JDBC API的調(diào)用細(xì)節(jié),并能自動(dòng)將結(jié)果集轉(zhuǎn)換成 Java Bean對(duì)象,大大簡(jiǎn)化了 Java數(shù)據(jù)庫(kù)編程的重復(fù)工作。
因?yàn)镸yBatis需要程序員自己去編寫(xiě)sql語(yǔ)句,程序員可以結(jié)合數(shù)據(jù)庫(kù) 自身的特點(diǎn)靈活控制sql語(yǔ)句,因此能夠?qū)崿F(xiàn)比Hibernate等全自動(dòng)orm 框架更高的查詢效率,能夠完成復(fù)雜查詢。
11、簡(jiǎn)述Mybatis的Xml映射文件和Mybatis內(nèi)部數(shù)據(jù)結(jié)構(gòu)之間的映射 關(guān)系?
Mybatis將所有Xml配置信息都封裝到All-In-One重量級(jí)對(duì)象 Configuration內(nèi)部。
在Xml映射文件中,<parameterMap>標(biāo)簽會(huì)被解 析為ParameterMap對(duì)象,其每個(gè)子元素會(huì)被解析為ParameterMapping 對(duì)象。<resultMap>標(biāo)簽會(huì)被解析為ResultMap對(duì)象,其每個(gè)子元素會(huì) 被解析為 ResultMapping 對(duì)象。每一個(gè)〈select〉、〈insert〉、 〈update〉、<delete>標(biāo)簽均會(huì)被解析為MappedStatement對(duì)象,標(biāo)簽 內(nèi)的sql會(huì)被解析為BoundSql對(duì)象。
12、什么是MyBatis的接口綁定,有什么好處?
接口映射就是在MyBatis中任意定義接口,然后把接口里面的方法和SQL 語(yǔ)句綁定,我們直接調(diào)用接口方法就可以,這樣比起原來(lái)了 SqlSession提供 的方法我們可以有更加靈活的選擇和設(shè)置.
13、接口綁定有幾種實(shí)現(xiàn)方式,分別是怎么實(shí)現(xiàn)的?
接口綁定有兩種實(shí)現(xiàn)方式:
一種是通過(guò)注解綁定,就是在接口的方法上面加上@Select @Update等注解里面包含Sql語(yǔ)句來(lái)綁定
另外一種就是通過(guò) xml里面寫(xiě)SQL來(lái)綁定,在這種情況下,要指定xml映射文件里面的 namespace必須為接口的全路徑名。
14、什么情況下用注解綁定,什么情況下用xml綁定?
當(dāng)Sql語(yǔ)句比較簡(jiǎn)單時(shí)候,用注解綁定;當(dāng)SQL語(yǔ)句比較復(fù)雜時(shí)候,用xml綁 定,一般用xml綁定的比較多
15、MyBatis實(shí)現(xiàn)一對(duì)一有幾種方式?具體怎么操作的?
有聯(lián)合查詢和嵌套查詢,聯(lián)合查詢是幾個(gè)表聯(lián)合查詢,只查詢一次,通過(guò)在 resultMap里面配置association節(jié)點(diǎn)配置一對(duì)一的類就可以完成;嵌套查詢 是先查一個(gè)表,根據(jù)這個(gè)表里面的結(jié)果的外鍵id,去再另外一個(gè)表里面查詢 數(shù)據(jù),也是通過(guò)association配置,但另外一個(gè)表的查詢通過(guò)select屬性配 置。
16、Mybatis能執(zhí)行一對(duì)一、一對(duì)多的關(guān)聯(lián)查詢嗎?都有哪些實(shí)現(xiàn)方式, 以及它們之間的區(qū)別?
能。
Mybatis不僅可以執(zhí)行一對(duì)一、一對(duì)多的關(guān)聯(lián)查詢,還可以執(zhí)行多對(duì) ―,多對(duì)多的關(guān)聯(lián)查詢,多對(duì)一查詢,其實(shí)就是一對(duì)一查詢,只需要把 selectOne。修改為selectList。即可;多對(duì)多查詢,其實(shí)就是一對(duì)多查詢,只 需要把selectOne。修改為selectList。即可。
關(guān)聯(lián)對(duì)象查詢,有兩種實(shí)現(xiàn)方式,一種是單獨(dú)發(fā)送一個(gè)sql去查詢關(guān)聯(lián)對(duì) 象,賦給主對(duì)象,然后返回主對(duì)象。另一種是使用嵌套查詢,嵌套查詢的 含義為使用join查詢,一部分列是A對(duì)象的屬性值,另外一部分列是關(guān)聯(lián) 對(duì)象B的屬性值,好處是只發(fā)一個(gè)sql查詢,就可以把主對(duì)象和其關(guān)聯(lián)對(duì) 象查出來(lái)。
17、MyBatis里面的動(dòng)態(tài)Sql是怎么設(shè)定的?用什么語(yǔ)法?
MyBatis里面的動(dòng)態(tài)Sql 一般是通過(guò)if節(jié)點(diǎn)來(lái)實(shí)現(xiàn),通過(guò)OGNL語(yǔ)法來(lái)實(shí) 現(xiàn),但是如果要寫(xiě)的完整,必須配合where,trim節(jié)點(diǎn),where節(jié)點(diǎn)是判斷包含 節(jié)點(diǎn)有內(nèi)容就插入where,否則不插入,trim節(jié)點(diǎn)是用來(lái)判斷如果動(dòng)態(tài)語(yǔ)句是 以and或or開(kāi)始,那么會(huì)自動(dòng)把這個(gè)and或者or取掉。
18、Mybatis是如何將sql執(zhí)行結(jié)果封裝為目標(biāo)對(duì)象并返回的?都有哪些 映射形式?
第一種是使用<resultMap>標(biāo)簽,逐一定義列名和對(duì)象屬性名之間的映 射關(guān)系。
第二種是使用sql列的別名功能,將列別名書(shū)寫(xiě)為對(duì)象屬性名,比如 T_NAME AS NAME,對(duì)象屬性名一般是name,小寫(xiě),但是列名不區(qū)分大 小寫(xiě),Mybatis會(huì)忽略列名大小寫(xiě),智能找到與之對(duì)應(yīng)對(duì)象屬性名,你甚 至可以寫(xiě)成 T_NAME AS NaMe, Mybatis 一樣可以正常工作。
有了列名與屬性名的映射關(guān)系后,Mybatis通過(guò)反射創(chuàng)建對(duì)象,同時(shí)使用 反射給對(duì)象的屬性逐一賦值并返回,那些找不到映射關(guān)系的屬性,是無(wú)法 完成賦值的。
19、Xml映射文件中,除了常見(jiàn)的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>為sql片段標(biāo)簽,通過(guò)<include>標(biāo)簽引入sql片段,<selectKey>為不支持自增的主鍵生成策略標(biāo)簽。
20、當(dāng)實(shí)體類中的屬性名和表中的字段名不一樣,如何將查詢的結(jié)果封裝到指定pojo?
通過(guò)在查詢的sql語(yǔ)句中定義字段名的別名。
通過(guò)<resultMap>來(lái)映射字段名和實(shí)體類屬性名的一一對(duì)應(yīng)的關(guān)系。
21、模糊查詢like語(yǔ)句該怎么寫(xiě)
在java中拼接通配符,通過(guò)#{}賦值
在Sql語(yǔ)句中拼接通配符(不安全會(huì)引起Sql注入)
22、通常一個(gè)Xml映射文件,都會(huì)寫(xiě)一個(gè)Dao接口與之對(duì)應(yīng),Dao的工 作原理,是否可以重載?
不能重載,因?yàn)橥ㄟ^(guò)Dao尋找Xml對(duì)應(yīng)的sql的時(shí)候全限名+方法名的保存和尋找策略。接口工作原理為jdk動(dòng)態(tài)代理原理,運(yùn)行時(shí)會(huì)為dao生成 proxy,代理對(duì)象會(huì)攔截接口方法,去執(zhí)行對(duì)應(yīng)的sql返回?cái)?shù)據(jù)。
23、Mybatis映射文件中,如果A標(biāo)簽通過(guò)include引用了 B標(biāo)簽的內(nèi) 容,請(qǐng)問(wèn),B標(biāo)簽?zāi)芊穸x在A標(biāo)簽的后面,還是說(shuō)必須定義在A標(biāo)簽 的前面?
雖然Mybatis解析Xml映射文件是按照順序解析的,但是,被引用的B標(biāo) 簽依然可以定義在任何地方,Mybatis都可以正確識(shí)別。原理是,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)簽也 就可以正常解析完成了。
24、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重 復(fù)?
不同的Xml映射文件,如果配置了 namespace,那么id可以重復(fù);如果沒(méi) 有配置namespace,那么id不能重復(fù);畢竟namespace不是必須的,只 是最佳實(shí)踐而已。原因就是namespace+id是作為Map<String, MappedStatement>的key使用的,如果沒(méi)有namespace,就剩下id,那 么,id重復(fù)會(huì)導(dǎo)致數(shù)據(jù)互相覆蓋。有了 namespace,自然id就可以重 復(fù),namespace不同,namespace+id自然也就不同。
25、Mybatis中如何執(zhí)行批處理?
使用BatchExecutor完成批處理。
26、Mybatis都有哪些Executor執(zhí)行器?它們之間的區(qū)別是什么?
Mybatis 有三種基本的 Executor 執(zhí)行器,SimpleExecutor、 ReuseExecutor、 BatchExecutor。
SimpleExecutor:每執(zhí)行一次 update 或 select,就開(kāi)啟一個(gè) Statement對(duì)象,用完立刻關(guān)閉Statement對(duì)象。
ReuseExecutor :執(zhí)行 update 或 select,以 sql 作為 key 查找 Statement 對(duì)象,存在就使用,不存在就創(chuàng)建,用完后,不關(guān)閉Statement對(duì)象,而是放置于Map
BatchExecutor:完成批處理。
27、Mybatis中如何指定使用哪一種Executor執(zhí)行器?
在Mybatis配置文件中,可以指定默認(rèn)的ExecutorType執(zhí)行器類型,也可 以手動(dòng)給DefaultSqlSessionFactory的創(chuàng)建SqlSession的方法傳遞 ExecutorType 類型參數(shù)。
28、Mybatis執(zhí)行批量插入,能返回?cái)?shù)據(jù)庫(kù)主鍵列表嗎?
能,JDBC都能,Mybatis當(dāng)然也能。
29、Mybatis是否可以映射Enum枚舉類?
Mybatis可以映射枚舉類,不單可以映射枚舉類,Mybatis可以映射任何對(duì) 象到表的一列上。映射方式為自定義一個(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問(wèn)號(hào)占位符參數(shù)和獲取列查詢結(jié)果。
30、如何獲取自動(dòng)生成的(主)鍵值?
配置文件設(shè)置usegeneratedkeys為true
31、在mapper中如何傳遞多個(gè)參數(shù)?
直接在方法中傳遞參數(shù),xml文件用#{0} #{1}來(lái)獲取
使用@param注解:這樣可以直接在xml文件中通過(guò)#{name}來(lái)獲取
32、resultType resultMap 的區(qū)別?
類的名字和數(shù)據(jù)庫(kù)相同時(shí),可以直接設(shè)置resultType參數(shù)為Pojo類
若不同,需要設(shè)置resultMap將結(jié)果名字和Pojo名字進(jìn)行轉(zhuǎn)換
33、使用MyBatis的mapper接口調(diào)用時(shí)有哪些要求?
類型相同
Mapper接口方法名和mapper.xml中定義的每個(gè)sql的id相同
Mapper接口方法的輸入?yún)?shù)類型和mapper.xml中定義的每個(gè)sql的 parameterType的類型相同
Mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個(gè)sql的 resultType的類型相同
Mapper.xml文件中的namespace即是mapper接口的類路徑。
34、Mybatis比IBatis比較大的幾個(gè)改進(jìn)是什么?
有接口綁定,包括注解綁定sql和xml綁定Sql
動(dòng)態(tài)sql由原來(lái)的節(jié)點(diǎn)配置變成OGNL表達(dá)式
在一對(duì)一,一對(duì)多的時(shí)候引進(jìn)了 association,在一對(duì)多的時(shí)候引入了 collection節(jié)點(diǎn),不過(guò)都是在resultMap里面配置
35、IBatis和MyBatis在核心處理類分別叫什么?
IBatis里面的核心處理類交SqlMapClient,MyBatis里面的核心處理類叫做 SqlSession。
36、IBatis和MyBatis在細(xì)節(jié)上的不同有哪些?
在sql里面變量命名有原來(lái)的#變量#變成了#{變量}
原來(lái)的
變成了${變量}
原來(lái)在sql節(jié)點(diǎn)里面的class都換名字交type
原來(lái)的 queryForObject queryForList 變成了 selectOne selectList5)原來(lái)的 別名設(shè)置在映射文件里面放在了核心配置文件里