首頁 > 軟體

Java MyBatis本地快取原理詳解

2022-07-05 18:06:06

背景

出現了一次生產事故,事情是這樣的,我們有一個專案,Java存取資料庫的框架使用的是MyBatis。然後一個業務員在系統中查詢了一個訂單,發現這個訂單是未支付的狀態,於是業務員聯絡客戶,讓客戶支付,客戶支付完成後,業務員又去系統查詢,結果還是未支付狀態,重新整理了頁面也是一樣,不過過了一會就好了。業務員把這個延遲問題,反饋給了我們。我就看程式碼,只是一個簡單的select * from order where id = ?語句呼叫。這個時候就想到了我們今天故事的主角,MyBatis的快取機制。

發現問題

復現

public class Main {
  public static void main(String[] args) throws IOException, InterruptedException {
    SqlSessionFactory build = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    UsersMapper mapper = build.openSession().getMapper(UsersMapper.class);
    List<Users> users = mapper.selectAll();
    System.out.println(JSONUtil.toJsonStr(users));

    // 在這睡眠期間去使用update語句修改資料庫資訊。
    Thread.sleep(1000 * 10);
    List<Users> users1 = mapper.selectAll();
    System.out.println(JSONUtil.toJsonStr(users1));

  }
}

看到上面的問題,很自然的就想到之前面試時候背的八股文,MyBatis的一二級快取。

解決問題

其實這個問題,對於實效性不強的專案的話,完全可以和業務說,網路延遲,等一等就可以了。 如果說實用性比較強的專案,可以選擇禁用這個快取。不過這樣也會帶來一個問題,也就是沒有快取後,很多查詢,查詢結果相同的SQL語句,原本只需要執行一遍就可以,這裡會請求很多次。增高DB的IO負擔。

探究快取的原理

Sql查詢部分深入

在上一篇Java MyBatis是如何執行一條SQL語句的講MyBatis的文章中已經說到了,mapper會經過動態代理去執行SqlSession的query方法。

閱讀快取部分原始碼,需要跟隨查詢方法往下追著看。

接著,我們這裡可以看到,一個Switch有很多的case,很顯而易見,我們會進入Select中,隨後Select的程式碼塊中,又有很多個If判斷,因為我們的方法返回的是一個List,正好就命中了returnsMany方法。

最終呼叫SqlSession中的Select方法,到達這裡接著往裡追。

到達執行器處理SQL語句的這一塊了,可見封裝了很多層,再往下追。

初見快取

看到這裡,終於見到快取相關字樣了,這裡去CreateCacheKey,看到這裡我突然想起了,剛工作時候的一次面試,有個傻*面試官,問我說MyBatis的快取Key是怎麼生成,當時我真想給他兩耳巴。繼續摳下面的query方法,可以看到把上面生成的key作為引數傳了下來。

追到這裡就可以看到一個比較關鍵的程式碼了,從localCache中呼叫了GetObject方法
這裡看到下面的方法,從這裡可以證明,MyBatis預設就是用本地快取,所以寫程式碼的時候自然也要記得處理快取不一致的問題。

告一段落

到這裡這一篇文章就結束了。一般來說,作為Java工程師,在工作中還是經常用到MyBatis這個點的,如果你在面試中真的問到了這麼一道快取題。而那麼巧你就知道,那麼郎有情,妾有意,恭喜您,點亮漲薪1K的成就。希望大家在當前大環境這麼不好的情況下,多多學習,多多面試,提高核心競爭力,等大環境回暖各個年入50萬+。

番外篇-Myabtis建立CacheKey的演演算法。

回到這一行程式碼,可以看到這個方法返回的是一個CacheKey的JavaClass,先不急著看這個方法的具體實現,先去看下這個類的構成,和構造方法。

構造方法

這個CacheKey類一共有兩個構造方法,可以看到的在有參構造方法中,呼叫了無參方法,隨後呼叫了,updateAll方法,能在構造中被呼叫的一般都是比較重要的,一會來看一下這個方法的實現,先來看下無參構造中的幾個變數。
hashcode、multiplier、cout、updateList,值得注意的是hashCode和multiplier兩個成員變數,都給賦值了初始值。

這兩個變數記憶一下,然後去看updateAll方法。

這個方法比較簡單,遍歷了objects入參,傳入update方法,繼續去追update方法。

看到這裡可以看出這裡大概是計算HashCode的一個地方。只是最後會把算過的值放入UpdateList中。

隨後去看這個類的tostring方法。

這裡也就是具體的方法了

根據冒號分割,hashCode:checkSum:updateList的每個元素

再回過頭來看一下CreateCacheKey方法看下最後生成是什麼

最後答案留給評論互動吧。

結束語

到此這篇關於Java MyBatis本地快取原理詳解的文章就介紹到這了,更多相關Java MyBatis本地快取 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com