MyBatis 常見面試題總結

一、#{}和${}的區別是什麼?

注:這道題是面試官面試我同事的。java

答:mysql

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

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

注:這道題是京東面試官面試我時問的。面試

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

三、最佳實踐中,一般一個 Xml 映射文件,都會寫一個 Dao 接口與之對應,請問,這個 Dao 接口的工做原理是什麼?Dao 接口裏的方法,參數不一樣時,方法能重載嗎?

注:這道題也是京東面試官面試我時問的。數據庫

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

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

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

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

注:我出的。app

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

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

舉例:select _ from student,攔截 sql 後重寫爲:select t._ from (select \* from student)t limit 0,10

五、簡述 MyBatis 的插件運行原理,以及如何編寫一個插件。

注:我出的。

答:MyBatis 僅能夠編寫針對 ParameterHandlerResultSetHandlerStatementHandlerExecutor 這 4 種接口的插件,MyBatis 使用 JDK 的動態代理,爲須要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這 4 種接口對象的方法時,就會進入攔截方法,具體就是 InvocationHandlerinvoke()方法,固然,只會攔截那些你指定須要攔截的方法。

實現 MyBatis 的 Interceptor 接口並複寫 intercept()方法,而後在給插件編寫註解,指定要攔截哪個接口的哪些方法便可,記住,別忘了在配置文件中配置你編寫的插件。

六、MyBatis 執行批量插入,能返回數據庫主鍵列表嗎?

注:我出的。

答:能,JDBC 都能,MyBatis 固然也能。

七、MyBatis 動態 sql 是作什麼的?都有哪些動態 sql?能簡述一下動態 sql 的執行原理不?

注:我出的。

答:MyBatis 動態 sql 可讓咱們在 Xml 映射文件內,以標籤的形式編寫動態 sql,完成邏輯判斷和動態拼接 sql 的功能,MyBatis 提供了 9 種動態 sql 標籤 trim|where|set|foreach|if|choose|when|otherwise|bind

其執行原理爲,使用 OGNL 從 sql 參數對象中計算表達式的值,根據表達式的值動態拼接 sql,以此來完成動態 sql 的功能。

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

注:我出的。

答:第一種是使用<resultMap>標籤,逐必定義列名和對象屬性名之間的映射關係。第二種是使用 sql 列的別名功能,將列別名書寫爲對象屬性名,好比 T_NAME AS NAME,對象屬性名通常是 name,小寫,可是列名不區分大小寫,MyBatis 會忽略列名大小寫,智能找到與之對應對象屬性名,你甚至能夠寫成 T_NAME AS NaMe,MyBatis 同樣能夠正常工做。

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

九、MyBatis 能執行一對1、一對多的關聯查詢嗎?都有哪些實現方式,以及它們之間的區別。

注:我出的。

答:能,MyBatis 不只能夠執行一對1、一對多的關聯查詢,還能夠執行多對一,多對多的關聯查詢,多對一查詢,其實就是一對一查詢,只須要把 selectOne()修改成 selectList()便可;多對多查詢,其實就是一對多查詢,只須要把 selectOne()修改成 selectList()便可。

關聯對象查詢,有兩種實現方式,一種是單獨發送一個 sql 去查詢關聯對象,賦給主對象,而後返回主對象。另外一種是使用嵌套查詢,嵌套查詢的含義爲使用 join 查詢,一部分列是 A 對象的屬性值,另一部分列是關聯對象 B 的屬性值,好處是隻發一個 sql 查詢,就能夠把主對象和其關聯對象查出來。

那麼問題來了,join 查詢出來 100 條記錄,如何肯定主對象是 5 個,而不是 100 個?其去重複的原理是<resultMap>標籤內的<id>子標籤,指定了惟一肯定一條記錄的 id 列,MyBatis 根據列值來完成 100 條記錄的去重複功能,<id>能夠有多個,表明了聯合主鍵的語意。

一樣主對象的關聯對象,也是根據這個原理去重複的,儘管通常狀況下,只有主對象會有重複記錄,關聯對象通常不會重複。

舉例:下面 join 查詢出來 6 條記錄,1、二列是 Teacher 對象列,第三列爲 Student 對象列,MyBatis 去重複處理後,結果爲 1 個老師 6 個學生,而不是 6 個老師 6 個學生。

t_id t_name s_id

| 1 | teacher | 38 | | 1 | teacher | 39 | | 1 | teacher | 40 | | 1 | teacher | 41 | | 1 | teacher | 42 | | 1 | teacher | 43 |

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

注:我出的。

答:MyBatis 僅支持 association 關聯對象和 collection 關聯集合對象的延遲加載,association 指的就是一對一,collection 指的就是一對多查詢。在 MyBatis 配置文件中,能夠配置是否啓用延遲加載 lazyLoadingEnabled=true|false。

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

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

十一、MyBatis 的 Xml 映射文件中,不一樣的 Xml 映射文件,id 是否能夠重複?

注:我出的。

答:不一樣的 Xml 映射文件,若是配置了 namespace,那麼 id 能夠重複;若是沒有配置 namespace,那麼 id 不能重複;畢竟 namespace 不是必須的,只是最佳實踐而已。

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

十二、MyBatis 中如何執行批處理?

注:我出的。

答:使用 BatchExecutor 完成批處理。

1三、MyBatis 都有哪些 Executor 執行器?它們之間的區別是什麼?

注:我出的

答:MyBatis 有三種基本的 Executor 執行器,SimpleExecutorReuseExecutorBatchExecutor

SimpleExecutor每執行一次 update 或 select,就開啓一個 Statement 對象,用完馬上關閉 Statement 對象。

`ReuseExecutor執行 update 或 select,以 sql 做爲 key 查找 Statement 對象,存在就使用,不存在就建立,用完後,不關閉 Statement 對象,而是放置於 Map<String, Statement>內,供下一次使用。簡言之,就是重複使用 Statement 對象。

BatchExecutor執行 update(沒有 select,JDBC 批處理不支持 select),將全部 sql 都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個 Statement 對象,每一個 Statement 對象都是 addBatch()完畢後,等待逐一執行 executeBatch()批處理。與 JDBC 批處理相同。

做用範圍:Executor 的這些特色,都嚴格限制在 SqlSession 生命週期範圍內。

1四、MyBatis 中如何指定使用哪種 Executor 執行器?

注:我出的

答:在 MyBatis 配置文件中,能夠指定默認的 ExecutorType 執行器類型,也能夠手動給 DefaultSqlSessionFactory 的建立 SqlSession 的方法傳遞 ExecutorType 類型參數。

1五、MyBatis 是否能夠映射 Enum 枚舉類?

注:我出的

答:MyBatis 能夠映射枚舉類,不單能夠映射枚舉類,MyBatis 能夠映射任何對象到表的一列上。映射方式爲自定義一個 TypeHandler,實現 TypeHandlersetParameter()getResult()接口方法。TypeHandler 有兩個做用,一是完成從 javaType 至 jdbcType 的轉換,二是完成 jdbcType 至 javaType 的轉換,體現爲 setParameter()getResult()兩個方法,分別表明設置 sql 問號佔位符參數和獲取列查詢結果。

1六、MyBatis 映射文件中,若是 A 標籤經過 include 引用了 B 標籤的內容,請問,B 標籤可否定義在 A 標籤的後面,仍是說必須定義在 A 標籤的前面?

注:我出的

答:雖然 MyBatis 解析 Xml 映射文件是按照順序解析的,可是,被引用的 B 標籤依然能夠定義在任何地方,MyBatis 均可以正確識別。

原理是,MyBatis 解析 A 標籤,發現 A 標籤引用了 B 標籤,可是 B 標籤還沒有解析到,尚不存在,此時,MyBatis 會將 A 標籤標記爲未解析狀態,而後繼續解析餘下的標籤,包含 B 標籤,待全部標籤解析完畢,MyBatis 會從新解析那些被標記爲未解析的標籤,此時再解析 A 標籤時,B 標籤已經存在,A 標籤也就能夠正常解析完成了。

1七、簡述 MyBatis 的 Xml 映射文件和 MyBatis 內部數據結構之間的映射關係?

注:我出的

答:MyBatis 將全部 Xml 配置信息都封裝到 All-In-One 重量級對象 Configuration 內部。在 Xml 映射文件中,<parameterMap>標籤會被解析爲 ParameterMap 對象,其每一個子元素會被解析爲 ParameterMapping 對象。<resultMap>標籤會被解析爲 ResultMap 對象,其每一個子元素會被解析爲 ResultMapping 對象。每個<select>、<insert>、<update>、<delete>標籤均會被解析爲 MappedStatement 對象,標籤內的 sql 會被解析爲 BoundSql 對象。

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

注:我出的

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

面試題看似都很簡單,可是想要能正確回答上來,一定是研究過源碼且深刻的人,而不是僅會使用的人或者用的很熟的人,以上全部面試題及其答案所涉及的內容,在個人 MyBatis 系列博客中都有詳細講解和原理分析。

相關文章
相關標籤/搜索