關於Mybatis的幾件小事(二)

1、MyBatis緩存機制

1.簡介

  • Mybatis包含了一個很是強大的查詢緩存的特性,它能夠很是方便地配置和定製。
  • 緩存key極大提升查詢效率
  • MyBatis系統中默認定義了兩次緩存
  • 默認狀況下,只有一級緩存(SqlSession級別的緩存,也稱爲本地緩存)開啓。
  • 二級緩存須要手動開啓和配置,它是基於namespace級別的緩存。
  • 爲了提升擴展性,MyBatis定義了緩存接口cache。能夠經過實現Cache接口來自定義二級緩存。

2.一級緩存

  • 一級緩存,即本地緩存,做用域默認爲SqlSession。當Session flush或close後,該Session中的全部Cache將被清空。
  • 本地緩存不能被關閉,但能夠調用clearCache()來清空本地緩存,或者改變緩存的做用域。
  • 在mybatis3.1以後,能夠配置本地緩存的做用域,在mybatis.xml中配置localCacheScope屬性。
    -MyBatis利用本地緩存防止循環引用和加速重複嵌套查詢,默認值爲SESSION,這種狀況下會緩存一個會話中執行的全部查詢。若設置值爲STATEMENT,本地會話僅用在語句執行上,對相同SqlSession的不一樣調用將不會共享數據。
  • 同一個會話期間只要查詢過的數據都會被保存在當前SqlSession的一個Map中
    - key:hashCode+查詢的SqlId+編寫的sql查詢語句+參數java

    3.一級緩存失效狀況

  • 不一樣的SqlSession對應不一樣的一級緩存
  • 同一個SqlSession可是查詢條件不一樣
  • 同一個SqlSession兩次執行期間執行了任何一次增刪改操做。
  • 同一個SqlSession兩次查詢期間手動清空了緩存。sql

4.二級緩存

  • 二級緩存,全局做用域緩存
  • 二級緩存默認不開腔,須要手動配置。
  • MyBatis提供二級緩存的接口以及實現,緩存實現要求POJO實現Serializable接口。
  • 二級緩存在SqlSession關閉或提交以後纔會生效。
  • 使用步驟:
    1. 全局配置文件中開啓二級緩存
    2. 須要使用二級緩存的映射文件處使用cache配置緩存
    3. POJO實現Serializable接口。

4.緩存相關屬性

  • eviction="FIFO" :緩存回收策略
    - LRU(最近最少使用):移除最長時間不被使用的對象。
    - FIFO(先進先出):按對象進入緩存的順序來移除對象。
    - SOFT(軟引用):移除基於垃圾回收期狀態和軟引用規則的對象。
    - WEAK(弱引用):更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
    - 默認的是LRU數據庫

  • flushInterval:刷新間隔,單位毫秒
    - 默認狀況下不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。緩存

  • size:引用數目,正整數
    - 表明緩存最多能夠存儲多少個對象,太大容易致使內存溢出tomcat

  • readOnly:只讀,true/false
    - true:只讀緩存;會給全部調用者返回緩存對象的相同實例。這些對象不能被修改。這提供了很重要的性能優點。
    - false:讀寫緩存,會返回緩存對象的拷貝(經過序列化)。這會慢一些,可是安全,默認爲false。安全

5.緩存設置

  • 全局setting的cacheEnable
    - 配置二級緩存的開關,一級緩存一直是打開的。session

  • select標籤的useCache屬性
    - 配置這個select是否使用二級緩存。一級緩存一直是使用的。mybatis

  • sql標籤的flushCache屬性:
    - 增刪改默認爲true,sql執行後,會清空一級和二級緩存。查詢默認false。app

  • sqlSession.claerCache()
    - 用來清除一級緩存性能

  • 當在某一個做用域(一級緩存/二級緩存/Namespace)進行了增刪改操做化,默認該做用域下全部select中的緩存將被clear。

6.使用第三方緩存以後的查詢流程

  1. 查詢二級緩存。
  2. 若是二級緩存沒有,查詢一級緩存。
  3. 一級緩存也沒有,查詢數據庫。

2、MyBatis工做原理示意圖

3、MyBatis插件開發

1.MyBatis插件

  • MyBatis在四大對象的建立過程當中,都會有插件進行介入,插件能夠利用動態代理機制一層層的包裝目標對象,而實如今目標對象指向目標方法以前進行攔截的效果。
  • MyBatis容許在已映射語句執行過程當中的某一點進行攔截調用。
  • 默認狀況下,MyBatis容許使用插件來攔截的方法包括:
    Executor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)
    ParameterHandler(getParameterObject,setParameters)
    ResultSetHandler(handlerResultSets,handlerOuutputParameters)
    StatementHandler(prepare,parameterize,batch,update,query)

2.插件開發步驟

  1. 編寫插件實現Interceptor接口,並使用@Intercepts註解完成插件簽名。
@Intercepts({
    @Signature(type=StatementHandler.class,method="prepare",
              args={Connection.class})
})
public class MyPlugin implements Interceptor{}
  1. 在全局配置文件中註冊插件
<plugins>
    <plugin interceptor="com.desperado.plugin.MyPlugin">
          <property  name="username" value="tomcat"/>
     </plugin>
</plugins>

3.插件原理

  1. 按照插件註冊聲明,按照插件配置順序調用插件plugin方法,生成被攔截對象的動態代理。
  2. 多個插件依次生成目標對象的代理對象,層層包裹,先聲明的先包裹,造成代理鏈。
  3. 目標想法執行時依次從外到內執行intercept方法。
  4. 多個狀況下,咱們每每須要在某個插件中分離出來目標對象,能夠藉助MyBatis提供的SystemMateObject類來進行獲取最後一層的h以及target屬性的值。

4.Interceptor接口

  • intercept:攔截目標方法執行。
  • plugin:生成動態代理對象,可使用MyBatis提供的Plugin類的wrap方法。
  • setProperties:注入插件配置時設置的屬性。

5. 經常使用代碼

//1.分離代理對象。因爲會造成屢次代理,因此須要經過while循環分離出最終被代理的對象,從而方便提取信息。
MetaObject metaObject = SystemMetaObject.forObject(target);
while(metaObject.hasGetter("h")){
      Object h = metaObject.getValue("h");
      metaObject = SystemMetaObject.forObject(h);
}
//2.獲取到代理對象中包含的被代理的真實對象
Object obj = metaObject.getValue("target");
//3.獲取被代理對象的MetaObject方便進行信息提取
metaObject forObject  = SystemMetaObject.forObject(obj);

4、其餘操做

1.分頁操做

  • 分頁可使用PageHelper插件。
  • 使用步驟:
    - 導入相關的依賴,pagehelper.jar和jsqlparser.jar.
    - 在Mybatis全局配置文件中配置分頁插件
    - 使用PageHelper提供的方法進行分頁
    - 可使用更強大的PageInfo封裝返回結果。

2.批量操做

  • 默認的openSession()方法沒有參數,使用它建立的SqlSession具備以下特性:
    - 會開啓一個事務(也就是 不自動提交)
    - 鏈接對象會從由活動環境配置的數據源實例獲得。
    - 事務隔離級別將會使用驅動或數據源的默認設置。
    - 預處理語句不會被複用,也不會批量處理更新。

  • openSession方法的ExecutorType類型的參數,枚舉類型,取值以下:
    - SIMPLE:這個執行器類型不作特殊的事情(這是默認裝配的)。它爲每一個語句的執行建立一個新的預處理語句。
    - REUSE:這個執行器類型會複用預處理語句。
    - BATCH:這個執行器會批量執行全部更新語句。

  • 批量操做就是使用MyBatis提供的BATCH類型的Executor進行的,它的底層就是經過暫存sql的方式進行的。能夠保存sql到必定數量後發給數據庫執行一次。

  • 與Spring整合中。推薦額外配置一個能夠專門用來執行批量操做的sqlSession,須要使用的時候,注入配置的批量操做的SqlSession,經過它獲取到mapper映射器進行操做。

  • 批量操做是在session.commit()之後才發送sql語句給數據庫進行執行的。
  • 途觀想讓其提早執行,可使用sqlSession.flushStatements()方法,讓其執行刷到數據庫中進行執行。

3.存儲過程

  • 調用存儲過程
  1. select標籤中statementType="CALLABLE".
  2. 標籤體中調用語法
<select id="callProcedure" statementType="CALLABLE">
    call procedure_name(#{param1},#{param2})
</select>
  • mybatis對存儲過程的遊標提供了一個JdbcType=CURSOR的支持,能夠智能的把遊標讀取到的數據,映射到咱們聲明的結果集中。

4.自定義TypeHandler處理枚舉

  • 能夠經過自定義TypeHandler的形式來設置參數或者取出結果集的時候自定義參數封裝策略。
  • 步驟: 1. 實現TypeHandler接口或者繼承BaseTypeHandler。 2. 使用@MappedType定義處理的Java類型,使用@MappedJdbcTypes定義jdbcType類型。 3. 在定義結果集標籤或者參數處理的時候聲明使用自定義TypeHandler進行處理或者在全局配置TypeHandler要處理的javaType
相關文章
相關標籤/搜索