天天看點

談談MyBatis持久層架構

談談 MyBatis

源自官方文檔:MyBatis 是一款優秀的持久層架構,它支援自定義 SQL、存儲過程以及進階映射。MyBatis 免除了幾乎所有的 JDBC 代碼以及設定參數和擷取結果集的工作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java 對象為資料庫中的記錄。一句話就是對 JDBC 的封裝。

MyBatis 的優缺點

優點:

1:SQL 語句與 Java 代碼分離,便于統一管理。

2:提供 xml 标簽,支援動态 SQL 編寫。

3:消除了 JDBC 中大量備援的代碼,并通過資料庫連接配接池維護連接配接。

4:很好的與各種資料庫相容,能夠與 Spring 很好的內建。

5:提供對象關系映射标簽,支援對象與資料庫的 ORM 字段關系映射。

缺點:

1:SQL 語句編寫的工作量較大,尤其是字段多,關聯查詢複雜時對于 SQL 的基礎功底有一定要求。

2:對性能要求較高,需求變化較多的項目适合使用 MyBatis。

什麼是 ORM

對象關系映射(Object Relational Mapping,簡稱 ORM),描述實體類屬性和資料庫字段之間的映射關系,将面向對象語言程式中的對象自動持久化到關系型資料庫中,場景的 ORM 架構:Hibernate、MyBatis 等。

半自動和全自動 ORM 映射工具

Hibernate 屬于全自動 ORM 映射工具,使用 Hibernate 查詢關聯對象或關聯集合對象時,可以根據對象關系模型直接擷取。

MyBatis 屬于半自動 ORM 映射工具,使用 MyBatis 查詢關聯對象或關聯集合對象時,需要手動編寫 SQL 來完成。

JDBC 的不足和 MyBatis 的解決

1:JDBC 資料庫建立連結和釋放資源頻繁造成系統資源浪費進而影響系統性能。MyBatis 使用資料庫連接配接池管理資料庫連接配接。

2:JDBC 的 SQL 語句寫在代碼中造成代碼不易維護。MyBatis 将 SQL 語句配置在 mapper.xml 檔案中與 Java 代碼進行分離。

3:JDBC 的 SQL 語句傳參非常麻煩,where 條件不确定且占位符要與參數一意對應。MyBatis 自動将 Java 對象映射到 SQL 語句中。

4:JDBC 對結果集解析較為麻煩,SQL 語句變化導緻解析代碼變化且解析前需要周遊。MyBatis 自動将 Java 對象映射到 SQL 語句中。

MyBatis 的編碼步驟

1:建立 SqlSessionFactory。

2:通過 SqlSessionFactory 建立 SqlSession。

3:通過 SqlSession 執行資料庫操作。

4:調用 session.commit() 送出事務。

5:調用 session.close() 關閉會話。

MyBatis 中 #{} 和 ${} 的差別

${}

 是 properties 檔案中的變量占位符。用于标簽屬性值和 SQL 内部的靜态文本替換。

#{}

 是 SQL 語句參數的占位符。MyBatis 會将 SQL 語句中的 

#{}

 替換為 ? 号。

#{}

 方式能很大程度上防止 SQL 注入,一般使用 

#{}

 而不使用 

${}

${}

 無法防止SQL 注入,一般用于傳入資料庫對象,比如表名。

什麼是 SQL 注入

源自百度百科:SQL 注入即是指 web 應用程式對使用者輸入資料的合法性沒有判斷或過濾不嚴,攻擊者可以在 web 應用程式中事先定義好的查詢語句的結尾上添加額外的 SQL 語句,在管理者不知情的情況下實作非法操作,以此來實作欺騙資料庫伺服器執行非授權的任意查詢,進而進一步得到相應的資料資訊。一句話就是通過拼接非法的可執行的 SQL 語句非法擷取資料資訊。

MyBatis 的 mapper 接口調用的要求

1:mapper 接口的類路徑即是 mapper.xml 檔案中的 namespace 屬性值。

2:mapper 接口方法名和 mapper.xml 檔案中定義的每個 SQL 的 id 相同。

3:mapper 接口方法的入參類型和 mapper.xml 檔案中定義的每個 SQL 的 parameterType 的類型相同。

4:mapper 接口方法的傳回值類型和 mapper.xml 檔案中定義的每個 SQL 的 resultType 的類型相同。

MyBatis 中的一級緩存與二級緩存

一級緩存:基于 PerpetuaCache 的 HashMap 本地緩存,作用域為 Session。當 Session flush 或 close 後,該 Session 中的所有 Cache 就将被清空。

二級緩存:與一級緩存機制相同,也是基于 PerpetuaCache 的 HashMap 本地緩存,但其作用域為 namespaces。二級緩存可以自定義存儲源,例如 Ehcache。二級緩存會對一個 namespace 對應的 mapper.xml 檔案中所有的 select 操作結果都進行緩存,不同線程之間就可以共用二級緩存。

當某一個作用域,不管是一級緩存 Session 還是二級緩存 namespaces 進行了增删改操作,預設該作用域下所有 select 中的緩存将被清除。

二級緩存開啟:MyBatis 配置檔案中開啟 <cache />。

二級緩存的政策:<cache readOnly="true"/> 二級緩存傳回給所有調用者是同一個緩存對象執行個體,調用者更新緩存執行個體後可以會造成其他調用者調用時出現資料不一緻的情況。<cache readOnly="false"/> 二級緩存傳回給所有調用者是總緩存對象的拷貝,不同調用者擷取的是緩存對象的不同執行個體,各自維護各自的緩存對象,更新不會影響到其他的調用者。二級緩存預設使用安全的 <cache readOnly="false"/> 政策。

xml 檔案中,除了常見的 CRUD 标簽外還有哪些标簽

其他 5 個标簽 resultMap / parameterMap / sql / include / selectKey。

動态 SQL 的 9 個标簽:trim / where / set / foreach / if / choose / when / otherwise / bind。

mapper 接口的實作原理

mapper 接口的底層是通過 Map<String, MapperedStatement> 集合維護。key 為接口的路徑名 + 方法名拼接的字元串或 namespace + id,value 為 MapperedStatement 對象。MapperedStatement 對象即為 namespace 下的标簽 id 對應的對象,例如 namespace=”com.xpy.mapper.UserMapper” 下的 select / insert / update / delete 标簽 id=”getUserById” 對應的對象。接口的路徑名 + 方法名拼接的字元串,例如 com.xpy.mapper.UserMapper.getUserById 定位一個唯一的 MapperedStatement 對象。

MapperedStatement 對象唯一說明 mapper 接口中的的方法不能重載。

不同的 xml 檔案中,如果配置了 namespace,id 就可以重複,如果沒有配置 namespace,則 id 對應的資料就會造成覆寫。

mapper 接口的工作原理是 JDK 動态代理。MyBatis 運作時會使用 JDK 動态代理為 mapper 接口生成代理對象 proxy,代理對象 proxy 會攔截接口方法轉而去執行 MapperedStatement 對象,并将 SQL 的執行結果傳回。

MyBatis 分頁和分頁插件的原理

MyBatis 使用 RowBounds 對象進行分類,是針對 ResultSet 結果集執行的記憶體分頁。要實作實體分頁可以通過 SQL 中配置 LIMIT 參數或使用分頁插件。

分頁插件的原理是使用 MyBatis 提供的插件接口實作自定義插件,在插件的攔截方法内攔截待執行的 SQL 語句進行重寫,根據 dialect 方言添加對應的實體分頁語句和參數。

MyBatis 的插件運作原理

MyBatis 僅支援 ParameterHandler、ResultSetHandler、StatementHandler、Executor 這四種接口的插件。每當執行這四種接口對象的方法時,就會進入攔截方法,也就是 InvocationHandler 的 invoke 方法,攔截指定需要攔截的方法。

編寫一個插件隻需實作 MyBatis 的 Interceptor 接口并重寫 intercept 方法,然後在給插件編寫一個注解,指定要攔截哪一個接口的哪些方法,最後在配置檔案中配置編寫的插件。

MyBatis 如何将 SQL 執行結果封裝為目标對象傳回的

第一種是通過 resultMap 标簽逐一定義資料庫字段名和實體類屬性名之間的映射關系,第二種是使用别名,将資料庫字段名寫成實體類屬性名,例如 t_title as title。有了映射關系後,MyBatis 會通過反射建立對象,同時給對象的屬性逐一指派并傳回,找不到或沒有映射關系的屬性無法完成指派。

MyBatis 的動态 SQL 的執行原理

動态 SQL 是指可以在 xml 檔案中可以通過标簽的形式動态編寫 SQL,完成邏輯判斷和動态拼接 SQL 語句的功能。動态 SQL 的執行原理是使用 OGNL 從 SQL 參數對象中計算表達式的指,根據表達式的值動态拼接 SQL。

MyBatis 關聯查詢的實作方式及差別

MyBatis 支援一對一、一對多、多對一、多對多的關聯查詢。關聯對象查詢有兩種實作方式,第一種是單獨發送一個 SQL 語句去查詢關聯對象,指派給主對象并傳回主對象。第二種是使用嵌套查詢,使用 join 查詢,一部分列是 A 對象的屬性值,一部分列是 B 對象的屬性值,隻發送一個 SQL 語句就可以把主對象和其關聯對象全都查出來。

MyBatis 的 Executor 執行器

MyBatis 有三種基本的 Executor 執行器:SimpleExecutor、ReuseExecutor、BatchExecutor。這些執行器都嚴格限制在 SqlSession 生命周期範圍内。

SimpleExecutor:每執行一次 update 或 select,就開啟一個 Statement 對象,用完立刻關閉。

ReuseExecutor:執行 update 或 select 時,以 SQL 作為 key 查找 Statement 對象,存在就使用,不存在就建立,用完後不關閉,而是放到 Map<String, Statement> 中,供下一次使用。

BatchExecutor:在執行 update 時将所有 SQL 都添加到批進行中,等待統一執行,執行器緩存了多個 Statement 對象,每個 Statement 對象都是 addBatch 完畢後,等待逐一執行 executeBatch。JDBC 批處理不支援 select。

MyBatis 配置檔案中可以指定預設的 ExecutorType 執行器類型,也可以手動給 DefaultSqlSessionFactory建立 SqlSession 的方法傳遞 ExecutorType 參數類型。

MyBatis 是否可以映射 Enum 枚舉類

可以,MyBatis 可以映射任何對象到表的列上。映射方式為自定義一個 TypeHandler,實作 TypeHandler 的 setParameter 和 getResult 方法,setParameter 方法實作 javaType 到 jdbcType 的轉換,設定 SQL 占位符參數。getResult 方法實作 jdbcType 到 javaType 的轉換,擷取列查詢結果。

MyBatis 解析标簽規則

MyBatis 解析 xml 檔案是按照順序解析的,但 MyBatis 解析标簽時如果發現引用了另外一個标簽,但另外一個标簽尚未解析到,此時就會将此标簽标記為未解析狀态,繼續解析餘下的标簽,待所有标簽解析完畢,MyBatis 會重新解析被标記為未解析狀态的标簽,此時另一個标簽已經存在,也就正常解析完成了。是以如果一個标簽通過 include 引用了另外一個标簽的内容,則另外一個标簽可以定義在任何地方。

原文連結:https://www.kuangstudy.com/bbs/1462698745987616770

ssm

繼續閱讀