1、什么是Mybatis?
Mybatis是一個半ORM框架,封裝了JDBC,開發(fā)時只要關(guān)注SQL語句本身,不需要處理加載驅(qū)動,創(chuàng)建連接,床架statement等過程,直接編寫原生態(tài)sql語句,可以嚴(yán)格控制sql執(zhí)行性能、靈活度高。
Mybatis可以使用XML和注解來配置和映射原生信息,將POJO映射成數(shù)據(jù)庫中的記錄,避免了所有的JDBC代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集。
通過xml文件或注解的方式將要執(zhí)行的各種statement配置起來,并通過Java對象和statement中的sql的動態(tài)參數(shù)進(jìn)行映射生成最終執(zhí)行的sql語句,最后由Mybatis框架執(zhí)行sql并將結(jié)果映射成Java對象并返回。
2、Mybatis的優(yōu)點(diǎn)
基于SQL語句編寫,想當(dāng)靈活,不會對應(yīng)用程序或者數(shù)據(jù)庫的現(xiàn)有設(shè)計(jì)造成任何影響,SQL寫在XML里,解除了SQL和程序代碼的耦合,便于統(tǒng)一管理;提供XML標(biāo)簽,支持編寫動態(tài)SQL語句,可重用。
減少了代碼量,消除了JDBC大量代碼的冗余,不需要手動開關(guān)連接。
很好的與各種數(shù)據(jù)庫兼容。
與Spring能很好的集成。
提供映射標(biāo)簽,支持對象與數(shù)據(jù)庫的ORM字段關(guān)系映射;提供對象關(guān)系映射標(biāo)簽,支持對象關(guān)系組件維護(hù)。
3、Mybatis的缺點(diǎn)
SQL編寫的工作量較大,當(dāng)字段多,關(guān)聯(lián)表多時,對SQL語句的編寫需要一定的能力。
SQL語句依賴于數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫移植性查,不能隨意更換數(shù)據(jù)庫。
4、Mybatis使用場景
MyBatis專注于SQL本身,是一個足夠靈活的DAO層解決方案。
對性能的要求很高,或者需求變化較多的項(xiàng)目,如互聯(lián)網(wǎng)項(xiàng)目,MyBatis將是不錯的選擇。
5、Mybatis和Hibernate的比較
Mybatis是一個半ORM框框,需要程序員編寫SQL語句;
Mybatis直接編寫原生態(tài)sql,可以嚴(yán)格控制SQL性能,靈活度高,非常適合對數(shù)據(jù)模型要求不高的軟件開發(fā),因?yàn)檫@類軟件需求變化頻繁;但是Mybatis無法做到數(shù)據(jù)庫無關(guān)性,如果需要實(shí)現(xiàn)支持多種數(shù)據(jù)庫的軟件,則需要自定義多套sql映射文件。
Hibernate對象/關(guān)系映射能力強(qiáng),數(shù)據(jù)庫無關(guān)性好,對于關(guān)系模型要求高的軟件,可以使用Hibernate。
6、#{}和${}的區(qū)別
${}是字符串替換,主要用來獲取properties文件中的配置屬性,在處理${}時,就是直接把${}替換成變量的值,直接進(jìn)行sql拼接;
#{}是預(yù)編譯處理,Mybaties的占位符,可以用來防止sql注入,具體原理是,mybaties在床架prepareStatement時,會用?來替換#{},然后在指向SQL語句前,通過反射的方式在statement里set相應(yīng)的參數(shù)。
7、實(shí)體類的屬性名和表中的字段名不一樣
通過在sql語句中定義字段的別名,別名和實(shí)體類中的屬性名一樣。
通過resultMap來映射字段名和實(shí)體類屬性名的一一對應(yīng)關(guān)系。
8、like語句的編寫
在Java代碼中添加SQL通配符;
在SQL語句中拼接通配符,但是會引起SQL注入。
9、通常一個XML映射文件,都會有一個DAO接口與之對應(yīng),DAO的原理是什么?DAO接口的方法可以重載嗎?
DAO接口就是Mapper接口,接口的全限定名,就是映射文件的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法內(nèi)的參數(shù),就是傳遞給SQL的參數(shù)。
Mapper接口沒有實(shí)現(xiàn)類,當(dāng)調(diào)用接口方法時,接口全限定名+方法名作為key值,可以唯一定位一個MapperStatement,在Mybatis中,每一個 <select>、<insert>、<update>、<delete> 標(biāo)簽,都會被解析為一個MapperStatement對象。
Mapper接口里面的方法是不能重載的,因?yàn)槭褂萌薅?方法名的保存和尋找策略。
Mapper接口的工作原理,是使用JDK動態(tài)代理,Mybatis運(yùn)行時會使用JDK動態(tài)代理為Mapper接口生成代理對象proxy,代理對象會攔截接口方法,執(zhí)行MapperStatement的SQL,然后將SQL執(zhí)行結(jié)果返回。
10、Mybatis分頁
Mybatis使用RowBounds對象進(jìn)行分頁,針對ResultSet結(jié)果集執(zhí)行內(nèi)存分頁,不是物理分頁。可以在SQL內(nèi)直接書寫帶有物理分頁的參數(shù)來完成物理分頁功能,也可以使用分頁插件完成物理分頁。
11、Mybatis如何將SQL執(zhí)行結(jié)果封裝成目標(biāo)對象并返回的?有哪些映射形式?
一是使用resultMap標(biāo)簽,逐一定義數(shù)據(jù)庫列名和對象屬性名之間的映射關(guān)系。二是使用SQL列的別名功能,將別名書寫為對象屬性名。
映射關(guān)系設(shè)置好后,Mybatis通過反射創(chuàng)建對象,同時使用反射給對象的屬性逐一賦值,并返回,找不到映射關(guān)系的屬性是無法完成賦值的。
12、Mybatis的批量執(zhí)行?
使用foreach標(biāo)簽,foreach主要用在構(gòu)建in條件中,可以在SQL中進(jìn)行迭代一個集合。foreach元素的屬性主要有item,index,collection,open,separator,close。item表示集合中每一個元素進(jìn)行迭代時的別名,index指 定一個名字,用于表示在迭代過程中,每次迭代到的位置,open表示該語句以什么開始,separator表示在每次進(jìn)行迭代之間以什么符號作為分隔 符,close表示以什么結(jié)束,在使用foreach的時候最關(guān)鍵的也是最容易出錯的就是collection屬性,該屬性是必須指定的,但是在不同情況 下,該屬性的值是不一樣的。
如果傳入的是單參數(shù)且參數(shù)類型是一個List的時候,collection屬性值為list?
如果傳入的是單參數(shù)且參數(shù)類型是一個array數(shù)組的時候,collection的屬性值為array?
如果傳入的參數(shù)是多個的時候,我們就需要把它們封裝成一個Map了,當(dāng)然單參數(shù)也可以封裝成map,實(shí)際上如果你在傳入?yún)?shù)的時候,在breast里面也 是會把它封裝成一個Map的,map的key就是參數(shù)名,所以這個時候collection屬性值就是傳入的List或array對象在自己封裝的map 里面的key。
13、如何獲取自動生成的主鍵?
userGeneratedKeys="true" -----使用自增主鍵獲取主鍵值策略
keyProperty="id" ? ? ------指定對應(yīng)的主鍵屬性,即mybatis獲取到主鍵值以后,將這個值封裝給Javabean中的哪個屬性。
14、Mabatis中mapper傳遞多個參數(shù)
(1)順序傳參,DAO接口里面定義多個參數(shù),在XML中順序根據(jù)順序傳入:
(2)@Param注解傳參,在DAO接口使用@Param注解,在XML中根據(jù)注解的名稱使用對應(yīng)的參數(shù):
(3)封裝成map傳參:
(4)封裝成Java Bean傳參。
15、Mybatis的動態(tài)SQL的作用,原理和類型
Mybatis動態(tài)SQL可以在XML中以標(biāo)簽的形式編寫動態(tài)的SQL,執(zhí)行原理是根據(jù)表達(dá)式的值完成邏輯判斷并拼接SQL的功能。
有9種動態(tài)標(biāo)簽:trim|where|set|foreach|if|choose|when|otherwise|bind;
16、Mybatis的標(biāo)簽
<select>,<update>,<insert>,<delete>,<resultMap>,<parameterMap>,<sql>,<include>,<selectKey>,和動態(tài)標(biāo)簽。
17、Mybatis中的XML映射文件中,不同的XML映射文件,id是否可以重復(fù)?
不同的XML映射文件,如果配置了namespace,那么id就可以重復(fù);如果沒有配置namespace,那么id不能重復(fù)。
18、為什么說Mybatis是半自動ORM映射工具?和全自動有什么區(qū)別?
Hibernate就是全自動映射工具,使用Hibernate查詢關(guān)聯(lián)對象或者關(guān)聯(lián)集合對象時,可以根據(jù)對象關(guān)系模型直接獲取。
而Mybatis在查詢關(guān)聯(lián)對象或關(guān)聯(lián)集合對象時,需要手動編寫SQL完成。
19、Mybatis的一對一查詢
一對一查詢有聯(lián)合查詢和嵌套查詢。
聯(lián)合查詢是在resultMap里面配置associate節(jié)點(diǎn)配置一對一的類。
嵌套查詢是先查一個表,根據(jù)這個表里面的結(jié)果的外鍵id,再去另外一個表查詢,也通過associate配置,但另外一個表的查詢通過select屬性配置。
<association property="supervisor" javaType="Teacher"column="supervisor_id" select="selectSupervisor"/>
20、Mybatis的一對多查詢
一對多查詢有聯(lián)合查詢和前臺查詢。
聯(lián)合查詢是在resultMap里面配置collection節(jié)點(diǎn)配置一對一的類。
嵌套查詢是先查一個表,根據(jù)這個表里面的結(jié)果的外鍵id,再去另外一個表查詢,也通過collection配置,但另外一個表的查詢通過select屬性配置。
21、Mybatis的延遲加載
Mybatis僅支持associate關(guān)聯(lián)對象和collection關(guān)聯(lián)集合對象的延遲加載。在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)用。這就是延遲加載的基本原理。
22、Mybatis的一級緩存和二級緩存
一級緩存,基于PerpetualCache的HashMap本地緩存,其存儲作用域?yàn)镾ession,當(dāng)Session flush或close后,該Session中的所有Cache就將清空,默認(rèn)打開一級緩存。
二級緩存與一級緩存機(jī)制相同,默認(rèn)也采用PerpetualCache的HashMap存儲。不同之處是二級緩存的作用域?yàn)镸apper(Namespace),并且可自定義存儲源。默認(rèn)不打開二級緩存,要開啟二級緩存,使用二級緩存屬性類需要實(shí)現(xiàn)Serializable序列化接口,可在它的映射文件中配置<cache/>。
對于緩存數(shù)據(jù)更新機(jī)制,當(dāng)某一個作用域的緩存進(jìn)行了C/U/D操作后,默認(rèn)該作用域下所有的select中的緩存將被clear。
23、Mybatis的接口綁定?有哪些實(shí)現(xiàn)方式?
接口綁定,就是在Mybatis中任意定義接口,然后接口里面的方法和SQL語句綁定,我們直接調(diào)用接口方法就可以。
有注解綁定,就是在接口加上@Select、@Update等注解,里面包含SQL語句來綁定。
另外一種就是XML里面寫SQL來綁定,指定xml里面的namespace為類的全限定名。
當(dāng)SQL比較簡單時,可以用注解綁定。SQL比較復(fù)雜時使用XML綁定。
24、Mapper編寫有哪幾種方式?
第一種:接口實(shí)現(xiàn)類繼承SqlSessionDaoSupport:使用此種方法需要編寫mapper接口,mapper接口實(shí)現(xiàn)類、mapper.xml文件。
(1)在sqlMapConfig.xml中配置mapper.xml的位置;
(2)定義mapper接口;
(3)實(shí)現(xiàn)類集成SqlSessionDaoSupport mapper方法中可以this.getSqlSession()進(jìn)行數(shù)據(jù)增刪改查;
(4)spring 配置。
第二種:使用 org.mybatis.spring.mapper.MapperFactoryBean :
(1)在sqlMapConfig.xml中配置mapper.xml的位置,如果mapper.xml和mappre接口的名稱相同且在同一個目錄,這里可以不用配置;
(2)定義mapper接口;
(3)mapper.xml中的namespace為mapper接口的全限定名;mapper接口中的方法名和mapper.xml中的定義的statement的id保持一致 ;Spring中定義
第三種:使用mapper掃描器:
(1)mapper.xml文件編寫:
mapper.xml中的namespace為mapper接口的全限定名; mapper接口中的方法名和mapper.xml中的定義的statement的id保持一致; 如果將mapper.xml和mapper接口的名稱保持一致則不用在sqlMapConfig.xml中進(jìn)行配置。
(2)定義mapper接口:
注意mapper.xml的文件名和mapper的接口名稱保持一致,且放在同一個目錄
(3)配置mapper掃描器:
(4)使用掃描器后從spring容器中獲取mapper的實(shí)現(xiàn)對象。
25、Mybatis的運(yùn)行原理
Mybatis可以編寫針對ParameterHandler,ResultSetHandler,StatementHandler,Executor這4種接口的插件;Mybatis使用JDK動態(tài)代理,為需要攔截的接口生成代理對象以實(shí)現(xiàn)接口方法的攔截功能,沒當(dāng)執(zhí)行到這4種接口對象的方法時,就會進(jìn)入攔截方法,具體是InvocationHandler的invoke()方法。