Mybatis常見面試題總結!!

一 、什麼是Mybatis?

MyBatis是一個半ORM(對象關係映射)框架,它內部封裝了JDBC,開發時只須要關注SQL語句自己,不須要花費精力去加載驅動、建立鏈接、建立Statement等繁雜過程。程序員直接編寫原生態sql,能夠嚴格控制sql執行性能,靈活度高。java

Mybatis可使用XML或註解來配置和映射原生信息,將POJO映射成數據庫中的記錄,避免幾乎全部JDBC代碼和手動設置參數以及得到結果集。mysql

經過xml文件或註解的方式將要執行的各類statement配置起來,並經過java對象和 statement中sql的動態參數進行映射生成最終執行的sql語句,最後由Mybatis框架執行sql並將返回結果映射爲java對象並返回。(從執行sql到返回result的過程)。

2、Mybatis的優勢

  1. 基於SQL語句編程,至關靈活,不會對應用程序或者數據庫的現有設計形成任何影響,SQL寫在XML文件中,接觸SQL與程序代碼的耦合,便於統一管理;提供XML便籤,支持編寫動態SQL語句,並能夠重用。
  2. 與JDBC相比,減小了50%以上的代碼量,消除了JDBC大量冗餘的代碼,不須要手動開關鏈接。
  3. 很好的與各類數據庫兼容(由於MyBatis使用JDBC來鏈接數據,因此只要JDBC支持數據庫MyBatis都支持)。
  4. 可以與Spring框架很好的集成。
  5. 提供映射標籤,支持對象與數據庫的ORM字段關係映射;提供對象關係映射標籤,支持對象關係組件維護。

3、Mybatis框架的缺點

  1. SQL語句的編寫工做量較大,尤爲當字段多,關聯表多時,對開發人員編寫SQL語句的功底有必定要求。
  2. SQL語句依賴數據庫,致使數據庫移植性差,不能隨意更換數據庫。

4、MyBatis框架使用場合

MyBatis專一於SQL自己,是一個足夠靈活的DAO層解決方案。程序員

對性能的要求很高,或者對需求變化較多的項目,如互聯網項目,MyBatis將是不錯的選擇。面試

5、Mybatis與Hibernate有哪些不一樣

Mybatis不徹底是一個ORM框架,由於Mybatis須要程序員本身編寫SQL語句。sql

Mybatis直接編寫原生態SQL,能夠嚴格控制SQL執行性能,靈活度高,很是適合對關係數據模型要求不高的軟件開發,由於這類軟件需求變化頻繁,一旦需求變化要求迅速輸出成果。可是靈活的前提是Mybatis沒法作到數據庫無關性,若是須要實現支持多種數據庫的軟件,則須要自定義多套SQL映射文件,工做量大。數據庫

Hibernate對象/關係映射能力強,數據無關性好,對於關係模型要求高的軟件,若是用Hibernate開發能夠節省不少代碼,提升效率。編程

6、Mybatis是如何進行分頁的?分頁插件的原理是什麼?

MyBatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁而非物理分頁。能夠在SQL內直接書寫帶有物理分頁的參數來完成分頁功能。也可使用分頁插件來完成物理分頁。緩存

分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截執行的SQL,而後從新SQL,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。markdown

7、Mybatis是如何將SQL執行結果封裝爲目標對象並返回的?都有哪些映射形式?

第一種是使用標籤:逐必定義數據庫列明和對象屬性名之間的映射關係。mybatis

第二種是使用SQL列的別名功能:將列的別名書寫爲對象屬性名。

有了列名和屬性名的映射關係後,Mybatis經過反射建立對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關係的屬性是沒法賦值的。

8、Mybatis動態SQL有什麼用?執行原理?有哪些動態SQL?

Mybatis動態SQL能夠在xml映射文件內,以標籤的形式編寫動態sql,執行原理是根據表達式的值完成邏輯判斷並動態拼接SQL的功能。

Mybatis提供了9種動態SQL標籤: trim|where|set|foreach|if|choose|when|otherwise|bind

9、XML映射文件中,除了常見的select|insert|update|delete標籤以外,還有哪些標籤?

還有不少其餘的標籤,<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上動態sql的9個標籤,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中<sql>爲sql片斷標籤,經過<include>標籤引入sql片斷,<selectKey>爲不支持自增的主鍵生成策略標籤。

10、Mybatis的XML映射文件中,不一樣的XML映射文件,id是否能夠重複?

不一樣的XML映射文件,若是配置了namespace,那麼id能夠重複;若是沒有配置namespace,那麼id不能重複;

緣由是 namespace+id是做爲 Mapkey使用的,若是沒有 namespace,就剩下 id,那麼, id重複會致使數據互相覆蓋。有了 namespace,天然 id就能夠重複, namespace不一樣,那麼 namespace+id天然也就會不一樣。

11、爲何說Mybatis是半自動ORM映射工具?它與全自動的區別在哪裏?

Hibernate屬於全自動的ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,能夠根據對象關係模型直接獲取,因此它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,須要手動編寫SQL來完成,因此稱之爲半自動ORM映射工具。

12、Mybatis實現一對一有幾種方式?具體是怎麼操做的?

有聯合查詢和嵌套查詢,聯合查詢是幾個表聯合查詢,只查詢一次,經過在resultMap裏配置association節點配置一對一的類就能夠完成。

嵌套查詢是先查詢一個表,根據這個表裏的結果的外鍵id,再去另外一表裏查詢數據,也是經過association配置,可是另外一個表的查詢經過select屬性配置。

十3、Mybatis實現一對多有幾種方式,怎麼操做的?

有聯合查詢和嵌套查詢。聯合查詢是幾個表聯合查詢,只查詢一次,經過在resultMap裏面的collection節點配置一對多的類就能夠完成;嵌套查詢是先查詢一個表,再去另外一表裏查詢數據,也是經過配置collection,可是另外一表的查詢經過select節點配置。

實例

一對多關聯查詢

resultMap模板
 <resultMap id\="惟一的標識" type\="映射的pojo對象"\>  
  <id column\="表的主鍵字段或查詢語句中的別名字段" jdbcType\="字段類型" property\="映射pojo對象的主鍵屬性" />  
  <result column\="表的一個字段(能夠爲任意表的一個字段)" jdbcType\="字段類型" property\="映射到pojo對象的一個屬性"/>  
  <collection property\="pojo的集合屬性" ofType\="集合中的pojo對象"\>  
  <id column\="集合中pojo對象對應的表的主鍵字段" jdbcType\="字段類型" property\="集合中pojo對象的主鍵屬性" />  
  <result column\="能夠爲任意表的字段" jdbcType\="字段類型" property\="集合中的pojo對象的屬性" />  
  </collection\>  
 </resultMap\>
resultMap+collection模板
 <!-- 一對多關聯查詢 -->  
 <!--  
 【resultMap:將整個查詢結果映射到com.mybatis.pojo.User這個實體中】  
 【id:惟一的標識,後面的select語句中resultMap的值】  
 【type:映射的pojo對象,映射到com.mybatis.pojo.User這個實體中】  
 【autoMapping:autoMapping="true"自動映射,放在id或type後面】  
 結構:<resultMap id="惟一的標識" type="映射的pojo對象">  
 \-->  
 <resultMap type\="com.mybatis.pojo.User" id\="userMap"\>  
  <!--  
  【id:查詢列中的惟一標識,User中的惟一標識】  
  結構:<id column="表的主鍵字段或查詢語句中的別名字段" jdbcType="字段類型" property="映射pojo對象的主鍵屬性" />  
  【column:與數據庫表對應的字段,property:與實體對應的屬性,jdbcType能夠不用寫會自動映射】  
  結構:<result column="表的一個字段" jdbcType="字段類型" property="映射到pojo對象的一個屬性"/>  
  【假如數據庫中t\_User表中的主鍵爲user\_id,而實體屬性名稱爲userId,則這個配置應爲  
  <id column="user\_id" property="userId"/>,result也是同樣,相似hibernate實體映射文件配置】  
  \-->  
  <id column\="id" property\="id"/>  
  <result column\="username" property\="username"/>  
  <result column\="password" property\="password"/>  
  <result column\="nickname" property\="nickname"/>  
  <result column\="email" property\="email"/>  
  <result column\="email" property\="email"/>  
  <!--  
  【collection:對關聯查詢到的多條記錄映射到集合中】  
  【property:將關聯查詢到的多條記錄映射到com.mybatis.pojo.User類的roles屬性中】  
  【ofType:指定映射的集合屬性中pojo的類型,roles屬於com.mybatis.pojo.Role對象】  
  【autoMapping:autoMapping="true"自動映射,放在property或ofType後面】  
  結構:<collection property="pojo的集合屬性" ofType="集合中的pojo對象">  
  \-->  
  <collection property\="roles" ofType\="com.mybatis.pojo.Role"\>  
  <!--  
  【Role實體映射對應t\_role表】  
  【id:集合中pojo對象對應的表的主鍵字段】  
  結構:<id column="集合中pojo對象對應的表的主鍵字段" jdbcType="字段類型" property="集合中pojo對象的主鍵屬性" />  
  【column:與數據庫表對應的字段,property:與實體對應的屬性】  
  結構:<result column="能夠爲任意表的字段" jdbcType="字段類型" property="集合中的pojo對象的屬性" />  
  \-->  
  <id column\="roleid" property\="id"/>  
  <result column\="name" property\="name"/>  
  <result column\="description" property\="description"/>  
  <result column\="createtime" property\="createtime"/>  
  </collection\>  
 </resultMap\>

![ResultMap映射.png](file://C:/Users/10224683/Pictures/markdown/ResultMap%E6%98%A0%E5%B0%84.png?lastModify=1578624600)

十4、Mybatis是否支持延遲加載?若是支持,他的實現原理是什麼?

Mybatis僅僅支持association關聯對象和collection關聯集合對象的延遲加載。

association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,能夠配置是否啓用延遲加載:

 lazyLoadingEnable=ture|false

它的原理是,使用CGLIB建立目標對象的代理對象,當調用目標方法時,進入攔截器方法,好比調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨發送事先保存好的查詢關聯B對象的SQL,把B查詢上來,而後調用a.setB(b),因而a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。

固然,不光是Mybatis,幾乎全部的包括Hibernate,支持延遲加載的原理都是樣的。

十5、Mybatis的一級、二級緩存:

(1)一級緩存

基於PerpetualCacheHashMap本地緩存,其存儲做用域爲Session,當Session flush或close以後,該Session中全部Cache就將清空,默認打開一級緩存。

(2)二級緩存

二級緩存與一級緩存機制相同,默認也是採用PerpetualCacheHashMap存儲,不一樣在於其存儲做用域爲Mapper(namespace),並能夠自定義存儲源,如Ehcache。默認不打開二級緩存,須要開啓二級緩存,使用二級緩存屬性類須要實現Serializable序列化接口(可用來保存對象狀態)。可在它的映射文件中配置。

在MyBatis配置文件中:

 <settings\>      
  <!--開啓二級緩存-->  
  <setting name\="cacheEnabled" value\="true"/>  
 </settings\>

在須要開啓二級緩存的mapper.xml中加入caceh標籤

  

<cache><cache/>

讓使用二級緩存的POJO類實現Serializable接口

 public class User implements Serializable {}
對於緩存更新機制,當某一個做用域(一級緩存Session、二級緩存Namespace)進行了C/U/D操做後,默認該做用域下全部select中的緩存將被清除。

十6、#{}${}的區別是什麼?

是文件中的變量佔位符,它能夠用於標籤屬性值和內部,屬於靜態文本替換,好比​{driver}會被靜態替換爲com.mysql.jdbc.Driver。#{}是sql的參數佔位符,Mybatis會將sql中的#{}替換爲?號,在sql執行前會使用PreparedStatement的參數設置方法,按序給sql的?號佔位符設置參數值,好比ps.setInt(0, parameterValue)#{item.name}的取值方式爲使用反射從參數對象中獲取item對象的name屬性值,至關於param.getItem().getName()

十7、Dao接口裏的方法,參數不一樣時,方法能重載嗎?

Dao接口,就是人們常說的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法內的參數,就是傳遞給sql的參數。Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串做爲key值,可惟必定位一個MappedStatement,舉例:com.mybatis3.mappers.StudentDao.findStudentById,能夠惟一找到namespacecom.mybatis3.mappers.StudentDao下面id = findStudentByIdMappedStatement。在Mybatis中,每個<select>、<insert>、<update>、<delete>標籤,都會被解析爲一個MappedStatement對象。

Dao接口裏的方法,是不能重載的,由於是全限名+方法名的保存和尋找策略。

Dao接口的工做原理是JDK動態代理,Mybatis運行時會使用JDK動態代理爲Dao接口生成代理proxy對象,代理對象proxy會攔截接口方法,轉而執行MappedStatement所表明的sql,而後將sql執行結果返回。

十8、模糊查詢馬上語句該怎麼寫?

第一種:在java代碼中添加sql通配符

 string wildcardname \= 「%smi%」;  
 list<name\> names \= mapper.selectlike(wildcardname);
 <select id\=」selectlike」\>  
 select \* from foo where bar like #{value}  
 </select\>

第二種:在 sql 語句中拼接通配符,會引發 sql 注入

 string wildcardname \= 「smi」;  
 list<name\> names \= mapper.selectlike(wildcardname);
 <select id\=」selectlike」\>  
 select \* from foo where bar like "%"#{value}"%"  
 </select\>

參考

(1)Mybatis面試十五問

(2)《MyBatis的一對多查詢》

相關文章
相關標籤/搜索