【面試官之你說我聽】-MyBatis常見面試題

【面試官之你說我聽】-MyBatis常見面試題

歡迎關注文章系列,一塊兒學習 《提高能力,漲薪可待篇》
《面試知識,工做可待篇》
《實戰演練,拒絕996篇》
也歡迎關注微信公衆號【Ccww筆記】,原創技術文章第一時間推出
若是此文對你有幫助、喜歡的話,那就點個讚唄,點個關注唄!html

往期文章系列:java

精講#{}和${}的區別是什麼?

  • mybatis在處理#{}時,會將sql中的#{}替換爲?號,調用PreparedStatement的set方法來賦值。git

  • mybatis在處理${}時,就是把${}替換成變量的值。程序員

  • 使用#{}能夠有效的防止SQL注入,提升系統安全性。緣由在於:預編譯機制。預編譯完成以後,SQL的結構已經固定,即使用戶輸入非法參數,也不會對SQL的結構產生影響,從而避免了潛在的安全風險。github

  • 預編譯是提早對SQL語句進行預編譯,而其後注入的參數將不會再進行SQL編譯。咱們知道,SQL注入是發生在編譯的過程當中,由於惡意注入了某些特殊字符,最後被編譯成了惡意的執行操做。而預編譯機制則能夠很好的防止SQL注入。面試

既然${}會引發sql注入,爲何有了#{}還須要有${}呢?那其存在的意義是什麼?redis

#{}主要用於預編譯,而預編譯的場景其實很是受限,而${}用於替換,不少場景會出現替換,而這種場景可不是預編譯sql

數據庫連接中斷如何處理

數據庫的訪問底層是經過tcp實現的,當連接中斷是程序是沒法得知,致使程序一直會停頓一段時間在這,最終會致使用戶體驗很差,所以面對數據庫鏈接中斷的異常,該怎麼設置mybatis呢?數據庫

connection操做底層是一個循環處理操做,所以能夠進行時間有關的參數:緩存

  • max_idle_time : 代表最大的空閒時間,超過這個時間socket就會關閉
  • connect_timeout : 代表連接的超時時間

數據庫服務器活的槓槓的,可是由於網絡用塞,客戶端仍然連不上服務器端,這個時候就要設置timeout,別一直傻等着

在開發過程當中,常常遇到插入重複的現象,這種狀況該如何解決呢?

插入的過程通常都是分兩步的:先判斷是否存在記錄,沒有存在則插入不然不插入。若是存在併發操做,那麼同時進行了第一步,而後你們都發現沒有記錄,而後都插入了數據從而形成數據的重複

解決插入重複的思路 :

  • 先判斷數據庫是否存在數據,有的話則不進行任何操做。沒有數據的話,進行下一步;
  • 向redis set key,其中只有一個插入操做A會成功,其餘併發的操做(B和C...)都會失敗的 ;
  • 當set key 成功的操做A,開始執行插入數據操做,不管是否插入數據成功,都在須要將redis key刪除。【注】插入不成功能夠多嘗試幾回,增長成功的機率 ;
  • 然而set key 失敗的操做B和C,sleep一下,競爭贏的插入操做重複以上步驟。

總結:多線程同時插入數據,誰獲取鎖並插入數據成功了其餘線程不作任何操做。當插入數據失敗後,其餘線程搶鎖進行插入數據。

事務執行過程當中宕機的應對處理方式

數據庫插入百萬級數據的時候,還沒操做完,可是把服務器重啓了,數據庫會繼續執行嗎? 仍是直接回滾了?

不會自動繼續執行,不會自動直接回滾 ,但能夠依據事務日誌進行回滾或者進行執行。

事務開啓時,事務中的操做,都會先寫入存儲引擎的日誌緩衝中,在事務提交以前,這些緩衝的日誌都須要提早刷新到磁盤上持久化 ,兩種類型:

在事務執行的過程當中,除了記錄redo log,還會記錄必定量的undo log。

  • redo log :按語句的執行順序,依次交替的記錄在一塊兒
  • undo log: 主要爲事務的回滾服務。undo log記錄了數據在每一個操做前的狀態,若是事務執行過程當中須要回滾,就能夠根據undo log進行回滾操做。

Java客戶端中的一個Connection是否是在MySQL中就對應一個線程來處理這個連接呢?

Java客戶端中的一個Connection不是在MySQL中就對應一個線程來處理這個連接,而是:

監聽socket的主線程+線程池裏面固定數目的工做線程來處理的

高性能服務器端端開發底層主要靠I/O複用來處理,這種模式:

單線程+事件處理機制

在MySQL有一個主線程,這是單線程(與Java中到處強調多線程的思想有點不一樣哦),它不斷的循環查看是否有socket是否有讀寫事件,若是有讀寫事件,再從線程池裏面找個工做線程處理這個socket的讀寫事件,完事以後工做線程會回到線程池。

Mybatis中的Dao接口和XML文件裏的SQL是如何創建關係的?

  • 解析XML: 初始化SqlSessionFactoryBean會將mapperLocations路徑下全部的XML文件進行解析
    • 建立SqlSource: Mybatis會把每一個SQL標籤封裝成SqlSource對象,能夠爲動態SQL和靜態SQL
    • 建立MappedStatement: XML文件中的每個SQL標籤就對應一個MappedStatement對象 ,並由 Configuration解析XML
  • Dao接口代理: Spring中的FactoryBean 和 JDK動態代理返回了能夠注入的一個Dao接口的代理對象
  • 執行: 經過statement全限定類型+方法名拿到MappedStatement 對象,而後經過執行器Executor去執行具體SQL並返回

當實體類中的屬性名和表中的字段名不同,怎麼辦 ?

  • 經過在查詢的sql語句中定義字段名的別名,讓字段名的別名和實體類的屬性名一致
  • 經過<resultMap>來映射字段名和實體類屬性名的一一對應的關係。

模糊查詢like語句該怎麼寫?

  • 在Java代碼中添加sql通配符
string name = "%Ccww%"; 
list<name> names = mapper.selectName(name);
複製代碼
<select id="selectName"> 
	select * from users where name like #{value} 
</select>
複製代碼
  • 在sql語句中拼接通配符,會引發sql注入
<select id="selectName">
    select * from users where name like "%"#{value}"%"
</select>
複製代碼

什麼是MyBatis的接口綁定?有哪些實現方式?

接口綁定 : 在MyBatis中任意定義接口,而後把接口裏邊的方法和SQL語句綁定,咱們能夠直接調用接口方法,比起SqlSession提供的方法咱們能夠有更加靈活的選擇和設置

接口綁定有兩種實現方式 :

  • 經過註解綁定: 在接口的方法上加上 @Select、@Update等註解,裏面包含Sql語句來綁定;
  • 經過xml綁定 : 要指定xml映射文件裏面的namespace必須爲接口的全路徑名 。

使用MyBatis的mapper接口調用時要注意的事項

  • Mapper接口方法名和mapper.xml中定義的每一個sql的id相同;
  • Mapper接口方法的輸入參數類型和mapper.xml中定義的每一個sql 的parameterType的類型相同;
  • Mapper接口方法的輸出參數類型和mapper.xml中定義的每一個sql的resultType的類型相同;
  • Mapper.xml文件中的namespace便是mapper接口的類路徑。

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

  • Dao接口爲Mapper接口。

  • 接口的全限名爲映射文件中的namespace的值;

  • 接口的方法名爲映射文件中Mapper的Statement的id值;

  • 接口方法內的參數爲傳遞給sql的參數。

Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串做爲key值,可惟必定位一個MapperStatement。在Mybatis中,每個 <select>、<insert>、<update>、<delete>標籤,都會被解析爲一個MapperStatement對象

Mapper接口裏的方法,是不能重載的,由於是使用 全限名+方法名 的保存和尋找策略。Mapper 接口的工做原理是JDK動態代理,Mybatis運行時會使用JDK動態代理爲Mapper接口生成代理對象proxy,代理對象會攔截接口方法,轉而執行MapperStatement所表明的sql,而後將sql執行結果返回。

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

基於上面,能夠得知

Statement=namespace+id

若是配置了namespace能夠重複的 ,但若是沒有配置namespace的話,那麼相同的id就會致使覆蓋了。

Mybatis的一級、二級緩存的做用是什麼?

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

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

(3)對於緩存數據更新機制,當某一個做用域(一級緩存 Session/二級緩存Namespaces)的進行了C/U/D 操做後,默認該做用域下全部 select 中的緩存將被 clear。

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

Mybatis 使用 RowBounds 對象進行分頁,它是針對 ResultSet 結果集執行的內存分頁,而非數據庫分頁

在實際場景下,使用以下兩種方案:

  • 在 SQL 內直接書寫帶有數據庫分頁的參數來完成數據庫分頁功能
  • 也可使用分頁插件來完成數據庫分頁。

這二者都是基於數據庫分頁,差異在於前者是工程師手動編寫分頁條件,後者是插件自動添加分頁條件。


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

舉例:SELECT * FROM student ,攔截 SQL 後重寫爲:select * FROM student LIMI 0,10

目前市面上目前使用比較普遍的 MyBatis 分頁插件有:

Mybatis 動態 SQL 是作什麼的?都有哪些動態 SQL ?能簡述一下動態 SQL 的執行原理嗎?

  • Mybatis 動態 SQL ,可讓咱們在 XML 映射文件內,以 XML 標籤的形式編寫動態 SQL ,完成邏輯判斷和動態拼接 SQL 的功能。
  • Mybatis 提供了 9 種動態 SQL 標籤:
    • <if>
    • <choose>
    • <when>
    • <otherwise>
    • <trim>
    • <where>、
    • <set>
    • <foreach>
    • <bind>
  • 其執行原理爲,使用 OGNL 的表達式,從 SQL 參數對象中計算表達式的值,根據表達式的值動態拼接 SQL ,以此來完成動態 SQL 的功能

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都有哪些Executor執行器?它們之間的區別是什麼?

Mybatis有三種基本的Executor執行器,SimpleExecutor、ReuseExecutor、BatchExecutor。

  • **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生命週期範圍內

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

MyBatis與Hibernate區別

  • hibernate是全自動,而mybatis是半自動
  • hibernate數據庫移植性遠大於mybatis
  • hibernate擁有完整的日誌系統,mybatis則欠缺一些
  • mybatis相比hibernate須要關心不少細節
  • sql直接優化上,mybatis要比hibernate方便不少
  • 緩存機制上,hibernate要比mybatis更好一些

總結:

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

參考文章:

www.mybatis.cn/category/in…

www.cnblogs.com/huajiezh/p/…

svip.iocoder.cn/MyBatis/Int…

也歡迎關注微信公衆號【Ccww筆記】,原創技術文章第一時間推出
若是此文對你有幫助、喜歡的話,那就點個讚唄,點個關注唄!

img
相關文章
相關標籤/搜索