Java面試題沖刺第九天–MyBatis2
面試題1:說說你對Mybatis的理解?
Mybatis是一個持久層的框架
,是apache下的頂級項目。
Mybatis內部封裝瞭jdbc,開發者隻需要關註sql語句本身,而不需要花費精力去處理加載驅動、創建連接、創建statement等繁雜的過程。
mybatis通過xml
或註解
的方式將要執行的各種statement配置起來,並通過java對象和statement中sql的動態參數進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射為java對象並返回。
MyBatis 支持定制化 SQL、存儲過程以及高級映射
。MyBatis 避免瞭幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJO映射成數據庫中的記錄。
追問1:說一下MyBatis的工作原理和流程吧。
1.讀取 MyBatis 配置文件
:mybatis-config.xml
為 MyBatis 的全局配置文件,配置瞭 MyBatis 的運行環境等信息,例如數據庫連接信息。
2.加載映射文件
:映射文件即 SQL 映射文件,該文件中配置瞭操作數據庫的 SQL 語句,需要在 MyBatis 配置文件 mybatis-config.xml 中加載。
3.構造會話工廠
:通過 MyBatis 的環境等配置信息構建會話工廠 SqlSessionFactory
。
4.創建會話對象
:由會話工廠創建 SqlSession
對象,該對象中包含瞭執行 SQL 語句的所有方法。
5.Executor 執行器
:MyBatis 底層定義瞭一個 Executor 接口來操作數據庫
,它將根據 SqlSession 傳遞的參數動態地生成需要執行的 SQL 語句,同時負責查詢緩存的維護
。
6.MappedStatement 對象
:在 Executor 接口的執行方法中有一個 MappedStatement
類型的參數,該參數是對映射信息的封裝,用於存儲要映射的 SQL 語句的 id、參數等信息。
7.輸入參數映射
:輸入參數類型可以是 Map、List 等集合類型,也可以是基本數據類型和 POJO 類型。輸入參數映射過程類似於 JDBC 對 preparedStatement 對象設置參數的過程。
8.輸出結果映射
:輸出結果類型可以是 Map、 List 等集合類型,也可以是基本數據類型和 POJO 類型。輸出結果映射過程類似於 JDBC 對結果集的解析過程。
追問2:列舉幾個MyBatis的核心組件,說說分別幹啥用?
組件名稱 | 功能 |
---|---|
SqlSession | MyBatis工作的主要頂層API,用於和數據庫交互的會話,完成必要數據庫增刪改查功能 |
Executor | MyBatis執行器,是MyBatis 調度的核心,負責SQL語句的生成和查詢緩存的維護 |
StatementHandler | 封裝瞭JDBC Statement操作,負責對JDBC statement 的操作,如設置參數、將Statement結果集轉換成List集合。 |
ParameterHandler | 負責對用戶傳遞的參數轉換成JDBC Statement 所需要的參數, |
ResultSetHandler | 負責將JDBC返回的ResultSet結果集對象轉換成List類型的集合; |
TypeHandler | 負責java數據類型和jdbc數據類型之間的映射和轉換 |
MappedStatement | 維護一條<select|update|delete|insert>節點的封裝, |
SqlSource | 負責根據用戶傳遞的parameterObject,動態生成SQL語句,將信息封裝到BoundSql對象中,並返回 |
BoundSql | 表示動態生成的SQL語句以及相應的參數信息 |
Configuration | MyBatis所有的配置信息都維持在Configuration對象之中。 |
面試題2:(問幾個實際使用的問題)Mybatis動態sql是做什麼的?都有哪些動態sql?
動態sql是指在進行sql操作的時候,傳入的參數對象或者參數值,根據匹配的條件,有可能需要動態的去判斷是否為空、循環、拼接等情況,用於輔助開發者更方便的進行半自動化的SQL開發;
Mybatis動態sql可以讓我們在Xml映射文件內,以標簽的形式編寫動態sql,完成邏輯判斷和動態拼接sql的功能。
Mybatis提供瞭9種動態sql標簽:trim
、where
、set
、foreach
、if
、choose
、when
、otherwise
、bind
。
其執行原理為,使用OGNL從sql參數對象中計算表達式的值,根據表達式的值動態拼接sql,以此來完成動態sql的功能。
追問1:Xml映射文件中,除瞭常見的select|insert|updae|delete標簽之外,你還常用哪些標簽?
用於Mybatis的Mapper文件中,有很多常見標簽如:<resultMap>
、<parameterMap>
、<sql>
、<include>
、<namespace>
等等,需要的話可以挨個解釋一下其作用。
追問2:Mybatis是如何將sql執行結果封裝為目標對象並返回的?都有哪些映射形式?
我們首先要根據代碼中實體類和數據表中的列名是否一一對應,如果對應上就可以直接返回。但多字段無法對應的情況怎麼返回?
第一種:使用sql列的別名功能,將列的別名書寫為對象屬性名,強行與實體類保持一致,但不方便維護。
第二種:使用resultMap
標簽,逐一定義數據庫列名和對象屬性名之間的映射關系,處理起來就比較清晰。
<resultMap type="com.xxxx.entity.Task" id="task"> <id column="taskId" property="id"/> <result column="taskName" property="task_name"/> <result column="frequency" property="frequency"/> <result column="updateTime" property="updateTime"/> <result column="description" property="description"/> <result column="modifier" property="modifier"/> <result column="remark" property="remark"/> </resultMap>
有瞭列名與屬性名的映射關系後,Mybatis通過反射創建對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關系的屬性,是無法完成賦值的。
追問3:MyBatis中接口綁定你都用過哪幾種方式?
我們一般通過註解綁定或在Mapper中進行綁定:
1.註解綁定
:在接口的方法上面加上 @Select
、@Update
等註解裡面包含Sql語句來綁定,Sql語句比較簡單的時候,推薦註解綁定。
2.Mapper標簽綁定
:通過xml裡面寫SQL來綁定, 指定xml映射文件裡面的namespace必須為接口類的全路徑名
,select標簽中的id來定義接口名稱
,須一一對應。
<mapper namespace="com.xxxxx.dao.TaskDao"> <!-- 查詢任務信息 --> <select id="getAllTaskDao" parameterType="int" resultMap="task" > SELECT taskId,taskName,frequency,updateTime,description,modifier,remark from task_info </select> </mapper>
追問4:我們知道insert 方法總是返回一個int值 ,這個值代表的是插入的行數。那我如何獲取自動生成的主鍵(id)值?
如果采用自增長策略,自動生成的鍵值在 insert 方法執行完後可以被設置到傳入的參數對象中。
<insert id=”insertUser” usegeneratedkeys=”true” keyproperty=”id”> insert into users_info (id,name) values (null,#{name}) </insert>
追問5:有兩個XML文件和這個Dao建立關系,如何避免沖突?
不管有幾個XML和Dao建立關系,隻要保證namespace+id唯一即可。
面試題3:用過Mybatis的一級、二級緩存麼?用過的話說一下原理。
先說緩存,合理使用緩存是優化中最常見的,將從數據庫中查詢出來的數據放入緩存中,下次使用時不必從數據庫查詢,而是直接從緩存中讀取,避免頻繁操作數據庫,減輕數據庫的壓力,同時提高系統性能。
一級緩存
一級緩存是SqlSession級別的緩存
。在操作數據庫時需要構造sqlSession對象,在對象中有一個數據結構用於存儲緩存數據。不同的sqlSession之間的緩存數據區域是互相不影響的。也就是他隻能作用在同一個sqlSession中,不同的sqlSession中的緩存是互相不能讀取的。
一級緩存的工作原理:
- 與Redis同理,用戶發起查詢請求,查找某條數據,sqlSession先去緩存中查找,是否有該數據,如果有,直接返回;如果沒有,從數據庫中查詢,並將查詢到的數據放入一級緩存區域,供下次查找使用。
- 但sqlSession執行commit,即
增刪改
操作時會清空緩存。這麼做的目的是避免臟讀。
二級緩存
為什麼要有二級緩存?
二級緩存是mapper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存
,二級緩存是跨SqlSession的。二級緩存的作用范圍更大。
在實際開發中,MyBatis通常和Spring進行整合開發。Spring將事務放到Service中管理,對於每一個service中的sqlsession是不同的,這是通過mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer創建sqlsession自動註入到service中的。 每次查詢之後都要進行關閉sqlSession,關閉之後數據即被清空。所以spring整合之後,如果沒有事務,一級緩存是沒有意義的。
二級緩存的配置方式
MyBatis對二級緩存的支持粒度很細,它會指定某一條查詢語句是否使用二級緩存。
3個必要配置:
MyBatis支持二級緩存的總開關,全局配置變量cacheEnabled=true
在mybatis-config.xml添加
<settings> <setting name="cacheEnabled" value="true"/><!-- 二級緩存 --> </settings>
該select語句所在的Mapper,配置<cache>
或<cached-ref>
節點
<mapper namespace="com.xxxx.dao.TaskDao"> <cache/> <insert id="addxxx" parameterType="xxx" > insert into xxx (name, price) values (#{name}, #{price}) </insert> <select id="listXXX" resultType="xxx"> select * from xxx </select> </mapper>
該select語句的參數 useCache=true
<select id="selectXXXX" resultMap="task" parameterType="java.util.Map" useCache="true">
追問1:一級緩存和二級緩存的使用順序
MyBatis查詢數據的順序是:
二級緩存 👉 一級緩存 👉 數據庫
總結
本篇文章就到這裡瞭,希望能給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- Mybatis 一級緩存和二級緩存原理區別
- 一篇文章帶你學習JAVA MyBatis底層原理
- Java經典面試題匯總:Mybatis
- Mybatis常見註解有哪些(總結)
- Mybatis結果集映射與生命周期詳細介紹