1. 程式人生 > >五、MyBatis快取

五、MyBatis快取

開發十年,就只剩下這套架構體系了! >>>   

一、MyBatis快取介紹

快取的使用可以明顯的加快訪問資料速度,提升程式處理效能,生活和工作中,使用快取的地方很多。在開發過程中,從前端-->後端-->資料庫等都涉及到快取。MyBatis作為資料訪問框架,也提供了快取功能,分別為:一級快取和二級快取。在使用MyBatis的時候,顯示或者預設的使用了快取。快取雖好,但是如果隨便使用,可能會導致很多問題,因此,有必要了解MyBatis快取的底層工作原理。

二、一級快取

1、工作原理

在應用程式執行時,在一個數據庫事務中,很可能一個查詢SQL執行多次,這裡就可以直接從快取中拿資料,而不必去查詢資料庫。因此,這裡MyBatis就設定了一級快取,來提高查詢效率。其流程如下:

對應的時序圖如下:

快取未命中時序圖:

快取命中:

快取key的生成規則為:MappedStatement.id+offset+limit+sql+property+environment,只有在key完全相同的情況下,參會被認為是命中。其程式碼如下:

 @Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    // mimic DefaultParameterHandler logic
    for (ParameterMapping parameterMapping : parameterMappings) {
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        String propertyName = parameterMapping.getProperty();
        if (boundSql.hasAdditionalParameter(propertyName)) {
          value = boundSql.getAdditionalParameter(propertyName);
        } else if (parameterObject == null) {
          value = null;
        } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
          value = parameterObject;
        } else {
          MetaObject metaObject = configuration.newMetaObject(parameterObject);
          value = metaObject.getValue(propertyName);
        }
        cacheKey.update(value);
      }
    }
    if (configuration.getEnvironment() != null) {
      // issue #176
      cacheKey.update(configuration.getEnvironment().getId());
    }
    return cacheKey;
  }

一級快取的查詢程式碼如下:


  @SuppressWarnings("unchecked")
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

2、注意事項

a、一級快取預設是開啟的,且其適用範圍為SESSION,其使用範圍是同一個SqlSession中的同一個事務中,跨事務的查詢是不會走到一級快取的,因為在第一個事務提交(還有insert、update、delete等操作)時,會執行clearLocalCache操作,這裡面會去清空一級快取。

b、預設的一級快取存在一個問題,如果在同一個事務A中,兩個相同SQL執行中間,另外一個事務提交了資料,那麼事務A中的第二次查詢就會讀取到髒資料(直接讀快取,未讀取資料庫)。對資料敏感的業務,需要設定一級快取的適用範圍為STATEMENT,這樣,每次執行一個sql,都會清空一級快取(相當於關閉了一級快取),下次查詢時,就會去查詢資料庫了。

三、二級快取

1、工作原理

二級快取是範圍更廣的快取,其適用範圍是一個namespace(這個namespace就是一個mapper xml檔案),也可以多個namespace共享一個二級快取。其執行流程如下:

二級快取執行程式碼如下:

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

預設情況下,二級快取是關閉的,需要主動開啟二級快取,配置方式如下:

a、在mybatis-config.xml中設定cacheEnabled=true(預設情況下,cacheEnabled也是true):

    <settings>
        <setting name="localCacheScope" value="SESSION"/>
        <setting name="cacheEnabled" value="true"/>
   <!--     &lt;!&ndash;開啟駝峰式命名,資料庫的列名能夠對映到去除下劃線駝峰命名後的欄位名&ndash;&gt;
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logImpl" value="LOG4J"/>-->
    </settings>

b、在mapper xml中配置cache標籤

<cache/>

2、注意事項

a、二級快取是範圍更加廣泛的快取,針對namespace級別,也可以跨namespace,這樣也更加容易產出髒資料,因此,一般不會開啟二級快取。

b、二級快取預設關閉,如果需要開啟,則需要單獨配置,如果需要開啟所有namespace的二級快取,目前MyBatis還不支援這樣的配置,可以進行優化(意義可能不大,因為二級快取使用的少)。

四、寫在最後

快取就如一把雙刃劍,有優點也有缺點,關鍵在於怎麼使用。優點就是可以提高資料訪問速度,缺點就是快取中資料可能和實際的資料(資料庫、遠端應用資料等)不一致。俗話說,任何脫離業務場景的架構都是耍流氓,對於快取的使用,同樣適用。

我們應該結合我們具體的業務場景來使用快取,針對本文,MyBatis的一二級快取,如果資料只查詢,不更新,那麼完全沒問題。

 

參考:

1、聊聊MyBatis快取機制

2、

相關推薦

MyBatis快取

開發十年,就只剩下這套架構體系了! >>>   

MyBatis-快取機制

MyBatis 包含一個非常強大的查詢快取特性,它可以非常方便地配置和定製。快取可以極大的提升查詢效率。MyBatis系統中預設定義了兩級快取, 一級 快取和 二級快取。– 1、預設情況下,只有一級快取(SqlSession級別的快取,也稱為本地快取)開啟,一級快取預設實現類org.apache.ibatis

Mybatis(3延遲載入查詢快取與ehcache整合逆向工程與spring整合)

版權宣告:本文為博主原創文章,未經博主允許不得轉載。    https://blog.csdn.net/www1056481167/article/details/70597788 延遲載入 延遲載入:先從單表查詢、需要時再從關聯表去關聯查詢,大大提高 資料庫效能,因為

mybatis基礎系列(四)——關聯查詢延遲載入一級快取與二級快取

關本文是Mybatis基礎系列的第四篇文章,點選下面連結可以檢視前面的文章: mybatis基礎系列(三)——動態sql mybatis基礎系列(二)——基礎語法、別名、輸入對映、輸出對映 mybatis基礎系列(一)——mybatis入門 關聯查詢 在進行表設計時,往往需要在具體的業務基礎上分析表與表之間的

mybatis和hibernate的一級二級快取

MyBatis一級快取: hibernate一級快取: 基本差不多  HashMap本地快取,作用域為session,session級別的快取,通過get,update可以將物件放到一級快取中,當 Session flush 或 close&n

Mybatis的一二級快取

  MyBatis快取介紹   Mybatis和Hibernate一樣,也有一級和二級快取,同樣預設開啟的只有一級快取,二級快取也需要手動配置開啟。        Mybatis 提供了快取機制減輕資料庫壓力,提高資料庫效能 一

MyBatis)一級快取和二級快取的區別

什麼叫快取將資料存放在程式記憶體中,用於減輕資料查詢的壓力,提升讀取資料的速度,提高效能。一級快取■ 兩個級別SqlSession級別的快取,實現在同一個會話中資料的共享Statement級別的快取,可以理解為快取只對當前執行的這一個Statement有效,執行完後就會清空快

[Swift通天遁地]高階擴充套件-(11)影象載入Loading動畫效果的自定義和快取

本文將演示影象載入Loading動畫效果的自定義和快取。 首先確保在專案中已經安裝了所需的第三方庫。 點選【Podfile】,檢視安裝配置檔案。 1 platform :ios, '12.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5

MyBatis 延遲載入,一級快取(sqlsession級別)二級快取(mapper級別)設定

什麼是延遲載入          resultMap中的association和collection標籤具有延遲載入的功能。         延遲載入的意思是說,在關聯查詢時,利用延遲載入,先載入主資訊。使用關聯資訊時再去載入關聯資訊。 設定延遲載入      

JAVAWEB開發之mybatis詳解(二)——高階對映查詢快取mybatis與Spring整合以及懶載入的配置和逆向工程

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "ht

Mybatis一級二級快取

一級快取 首先做一個測試,建立一個mapper配置檔案和mapper介面,我這裡用了最簡單的查詢來演示。 <mapper namespace="cn.elinzhou.mybatisTest.mapper.UserMapper">

面試記錄第十節——(bitmap釋放lru三級快取圖片壓縮)

一、recycle釋放記憶體問題 答: 在Android2.3.3(API 10)及之前的版本中,Bitmap物件與其畫素資料是分開儲存的,Bitmap物件儲存在Dalvik heap中,而Bitmap物件的畫素資料則儲存在Native Memor

OSGI企業應用開發(十)基於SpringMybatisSpring MVC實現一個登入應用

前面文章中,我們已經完成了OSGI應用中Spring、Mybatis、Spring MVC的整合,本篇文章我們就在這個基礎上來完成一個簡單的登入應用,其中使用者名稱和密碼需要從資料庫中查詢。 前面文章中,我們已經搭建好的工作空間如下圖所示: 本篇文章中,

spring boot整合mybatis-plus

nta 下劃線 問題 action least 類型 inter auto detail spring boot整合mybatis-plus 簡介 mybatis 增強工具包,簡化 CRUD 操作。 文檔 http://mp.baomidou.com http://myb

Mybatis一級快取二級快取詳講

  Mybatis 一級快取、二級快取 作者 : Stanley 羅昊 【轉載請註明出處和署名,謝謝!】 查詢快取 首先,我們先看一下這個標題“查詢快取”,那就說明跟增、刪、改是沒有任何關聯的,只有在查詢時,才會遇到快取,增刪改不涉及! 查詢快取目前Mybatis

MyBatis 一級快取二級快取全詳解(一)

目錄 MyBatis 一級快取、二級快取全詳解(一) 什麼是快取 什麼是MyBatis中的快取 MyBatis 中的一級快取 初探一級快取 探究一級快取是如何失效的

六章總結

間隔 項目開發 包括 溝通 區別 交流 backlog 每天 求和 第五章講的是關於團隊合作和具體的流程。在第一節當中,為我們講述了非團隊和團隊的區別;第二節講了幾種軟件團隊的模式,包括主治醫生模式、明星模式、社區模式。業余劇團模式等等;第三節為我們介紹了幾種開

IDEA下創建Maven項目,並整合使用SpringSpring MVCMybatis框架

varchar bat 連接 pom.xml文件 http mave eat supported 分享 項目創建 本項目使用的是IDEA 2016創建。項目使用Spring 4.2.6,Mybatis3.4.0,Tomcat使用的是Tomcat8,數據庫為MySQL。 首

類的加載機制和反射——使用反射生成JDK動態代理

復用 他也 new mil ont throwable logs object load 使用反射生成JDK動態代理 1.使用Proxy和InvocationHandler創建動態代理 (1)Proxy提供了用於創建動態代理類和動態代理對象的靜態方法,他也是所有動態代理類的

【軟件project】之第六章總結

term 方法 工作量 article mar sso 就會 jsb .net 軟件project的前幾章各自是軟件計劃、需求分析、軟件設計。整體的都規劃好了以後,就該著手去實踐了。所謂的理論體系足夠強大了以後,實踐就顯得尤為輕松。我們設計軟