我在個人簡歷上面沒有寫持久層框架,所以這方面在面試的過程問的也比較少,自己總結的也比較粗糙。問的最多的是第二點和第十點
一:工作流程
通過數據源創建一個數據庫連接,將創建的數據庫連接統一放到連接池進行管理,減少每次創建和斷開數據庫連接的開銷。通過Sqlsession去操作數據庫連接。
二:#{…} 和${…} 的區別
sql 注入只對 sql 語句的編譯過程有破壞作用,而 PreparedStatement 已經編譯好了,執行階段只是把輸入串作爲數據處理,而不再對 sql 語句進行解析,準備,因此也就避免了 sql 注入問題。
#{}是預編譯處理,$ {}是字符串替換。mybatis在處理#{}時,會將sql中的#{}替換爲?號,調用PreparedStatement的set方法來賦值;mybatis在處理 $ { } 時,就是把 ${ } 替換成變量的值。使用 #{} 可以有效的防止SQL注入,提高系統安全性
三:動態sql
If:經常用作非空判斷和真假判斷;
choose when otherwise:類似 switch case default;
Where:代替sql中的where 1=1,使sql語句正確
trim;用來去除特殊的字符
set:用於更新操作,只需要發送需要更新的字段,不用像Hibernate那樣發送整個pojo
Foreach:針對數組和集合進行循環遍歷(這是實現批量查詢的關鍵)
Select * from table_name where id in
<foreach item=”id” index=”index” collection=”list” open=”(” separator=”,” close=”)”>
#{id}
</foreach>
當傳入的是單參數且參數類型是數組或者list時,collection的值爲array和list
當傳入的多個參數,就需要將參數封裝成map,collection的值是Map的鍵
當傳入的是一個pojo時,collection的值爲該類中需要進行遍歷的數組或集合的屬性名
四:mybatis的關聯查詢
所謂關聯,就是在一個pojo中存在另外一個pojo。這兩個pojo的關係可能是一對一(一個用戶pojo唯一對應一個IdCard的pojo),一對多(一個用戶pojo對應多個訂單Order的pojo),多對多(一個訂單Order的pojo對應多個商品Product的pojo,反之一個商品Producet的pojo也可以對應多個訂單Order的pojo)。
實現方式有兩種:
嵌套查詢,通過select引入另外一個查詢的sql:缺點可能導致較多關聯sql被執行。
嵌套結果:只需要將所有要查詢的字段寫在一個從多表中進行查詢的sql,一次執行。
一對一:association;一對多:collection;多對多:collection,需要藉助一箇中間表。
五:逆向工程注意事項
selectByExample 和selectByExampleWithBLOBs 兩個方法的區別
1>兩個方法的返回的resultMap不同
selectByExample 方法返回:BaseResultMap
selectByExampleWithBLOBs 方法返回:ResultMapWithBLOBs
ResultMapWithBLOBs定義時,繼承了BaseResultMap,並且自己特殊的字段,該字段通常是longvarchar類型,
2>使用場景不同
若檢索大字段時,則需要使用selectByExampleWithBLOBs ,一般情況則使用selectByExample 即可。
六:常見的持久層框架
概念:
jdbc是java連接數據庫操作的原生接口
jpa是java持久化規範,是orm框架的標準,主流orm框架都實現了這個標準
spring data jpa是對jpa規範的再次抽象,底層還是用的實現jpa的hibernate技術
hibernate是一個標準的orm框架,實現了jpa
mybatis也是一個持久化框架,但不完全是一個orm框架,不是依照的jpa規範。
聯繫:
jdbc是比較底層的數據庫操作方式,hibernate和mybatis都是在jdbc的基礎上進行了封裝。
hibernate是將數據庫中的數據表映射爲持久層的java對象,實現對數據表的完整性控制。hibernate的主要思想是面向對象,標準的orm。不建議自己寫sql語句,如果確實有必要推薦hql代替。hibernate是全表映射,只需提供java bean和數據庫表映射關係,
mybatis是將sql語句中的輸入參數parameterMap和輸出結果resultMap映射爲java對象,放棄了對數據表的完整性控制,獲得了更大的靈活性。mybatis擁抱sql,在sql語句方面有更大的靈活性,mybatis不是面向對象,不是標準的orm,更像是sql mapping框架。mybatis是半自動的,需要提供java bean,sql語句和數據庫表的映射關係。
七:dbcp 和 c3p0 的區別
連接池的配置參數:
driverClassName:com.mysql.jdbc.Driver,
Url:jdbc:mysql://localhost:3306/taotao?characterEncoding=utf-8
Hostname:root
Password:root
dbcp 沒有自動的去回收空閒連接的功能 c3p0 有自動回收空閒連接功能 。C3P0提供最大空閒時間,DBCP提供最大連接數。前者當連接超過最大空閒連接時間時,當前連接就會被斷掉。DBCP當連接數超過最大連接數時,所有連接都會被斷開。所以dbcp會出現丟連接的情況。
八:xml文件和對應dao的關係
通常一個 Xml 映射文件,都會寫一個 Dao 接口與之對應,請問,這個 Dao 接口的工作原理是什麼?Dao 接口裏的方法,參數不同時,方法能重載嗎?
Dao接口,就是人們常說的 Mapper接口,接口的全限名,就是映射文件中的 namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法內的參數,就是傳遞給sql的參數。Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串作爲 key 值,可唯一定位一個 MappedStatement。Dao 接 口的工作原理是JDK動態代理,Mybatis 運行時會使用JDK 動態代理爲Dao接口生成代理proxy對象,代理對象proxy會攔截接口方法,轉而執行MappedStatement所代表的sql,然後將sql 執行結果返回。Dao接口裏的方法,是不能重載的,因爲是全限名+方法名的保存和尋找策略。
九:常見問題
1:當實體類中的屬性名和表中的字段名不一樣 ,怎麼辦 ?
第1種: 通過在查詢的sql語句中定義字段名的別名,讓字段名的別名和實體類的屬性名一致
第2種: 通過來映射字段名和實體類屬性名的一一對應的關係
十:緩存
Mybatis的一級緩存是SqlSession級別。第一次執行select時候會發現sqlsession緩存沒有記錄,會去數據庫查找,然後把結果保存到緩存,第二次同等條件查詢下,就會從緩存中查找到結果。另外爲了避免髒讀,每次執行更新新增刪除時候會清空當前sqlsession緩存。
怎麼判斷某兩次查詢是完全相同的查詢?
mybatis認爲,對於兩次查詢,如果以下條件都完全一樣,那麼就認爲它們是完全相同的兩次查詢。
2.1 傳入的statementId
2.2 查詢時要求的結果集中的結果範圍
2.3. 這次查詢所產生的最終要傳遞給JDBC java.sql.Preparedstatement的Sql語句字符串(boundSql.getSql() )
2.4 傳遞給java.sql.Statement要設置的參數值
二級緩存是namespace級別的。同一個namespace下的搜尋語句共享一個二級緩存。如果開啓了二級緩存,則先從二級緩存中查找,查找不到則委託爲SimpleExecutor查找,而它則會先從一級緩存中查找,查找不到則從數據庫查找。
一、創建一個POJO Bean並序列化
由於二級緩存的數據不一定都是存儲到內存中,它的存儲介質多種多樣,所以需要給緩存的對象執行序列化
二、在映射文件中開啓二級緩存
<!--
eviction:代表的是緩存回收策略,目前MyBatis提供以下策略。
(1) LRU,最近最少使用的,一處最長時間不用的對象
(2) FIFO,先進先出,按對象進入緩存的順序來移除他們
(3) SOFT,軟引用,移除基於垃圾回收器狀態和軟引用規則的對象
(4) WEAK,弱引用,更積極的移除基於垃圾收集器狀態和弱引用規則的對象。這裏採用的是LRU, 移除最長時間不用的對形象
flushInterval:刷新間隔時間,單位爲毫秒,這裏配置的是100秒刷新,如果你不配置它,那麼當 SQL被執行的時候纔會去刷新緩存。
size:引用數目,一個正整數,代表緩存最多可以存儲多少個對象,不宜設置過大。設置過大會導致內存溢出。 這裏配置的是1024個對象
readOnly:只讀,意味着緩存數據只能讀取而不能修改,這樣設置的好處是我們可以快速讀取緩存,缺點是我們沒有辦法修改緩存,默認值是false,不允許我們修改
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
三、在 mybatis-config.xml中開啓二級緩存
<settings>
<!--這個配置使全局的映射器(二級緩存)啓用或禁用緩存-->
<setting name="cacheEnabled" value="true" />
.....
</settings>