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

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

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

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

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

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

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

  • 預編譯是提前對SQL語句進行預編譯,而其後注入的參數將不會再進行SQL編譯。我們知道,SQL注入是發生在編譯的過程中,因爲惡意注入了某些特殊字符,最後被編譯成了惡意的執行操作。而預編譯機制則可以很好的防止SQL注入。

既然KaTeX parse error: Expected 'EOF', got '#' at position 17: …}會引起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 來完成。

參考文章:

http://www.mybatis.cn/category/interview/

https://www.cnblogs.com/huajiezh/p/6415388.html

http://svip.iocoder.cn/MyBatis/Interview/

也歡迎關注微信公衆號【Ccww筆記】,原創技術文章第一時間推出

img

如果此文對你有幫助、喜歡的話,那就點個讚唄,點個關注唄!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章