首頁 > 軟體

PageHelper引發的幽靈資料問題解析

2023-10-16 22:00:33

前言

最近測試反饋一個問題,某個查詢全量資訊的介面,有時候返回全量資料,符合預期,但是偶爾又只返回1條資料,簡直就是“見鬼”了,究竟是為什麼出現這樣的“幽靈資料”呢?

大膽猜測

首先我們看了下這對程式碼的業務邏輯,非常的簡單,總共沒有幾行程式碼,也沒有分頁邏輯,程式碼如下:

public  List<SdSubscription> findAll() {
    return sdSubscriptionMapper.selectAll();
}

那麼究竟是咋回事呢?講道理不可能出現這種情況的啊,不要慌,我們加點紀錄檔,將紀錄檔級別調整為DEBUG,讓紀錄檔飛一段時間。

public  List<SdSubscription> findAll() {
    log.info("find the sub start .....");
    List<SdSubscription> subs = sdSubscriptionMapper.selectAll();
     log.info("find the sub end .....");
    return subs;
}

果不其然,紀錄檔中出現了奇奇怪怪的分頁引數,如下圖所示:

果然是PageHelper這個開源框架搞的鬼,我想大家都用過吧,分頁非常方便,那麼究竟為什麼別人都沒問題,單單就我會出現問題呢?

PageHelper工作原理

為了回答上面的疑問,我們先看看PageHelper框架的工作原理吧。

PageHelper 是一個開源的 MyBatis 分頁外掛,它可以幫助開發者在查詢資料時,快速的實現分頁功能。

PageHelper 的工作原理可以簡單概括為以下幾個步驟:

  • 在需要進行分頁的查詢方法前,呼叫 PageHelper 的靜態方法 startPage(),設定當前頁碼和每頁顯示的記錄數。它會將分頁資訊放到執行緒的ThreadLocal中,那麼線上程的任何地方都可以存取了。
  • 當查詢方法執行時,PageHelper 會自動攔截查詢語句,如果發現執行緒的ThreadLocal中有分頁資訊,那麼就會在其前後新增分頁語句,例如 MySQL 中的 LIMIT 語句。
  • 查詢結果將被包裝在 Page 物件中返回,該物件包含分頁資訊和查詢結果列表。
  • 在查詢方法執行完畢後,會在finally中清除執行緒ThreadLocal中的分頁資訊,避免分頁設定對其他查詢方法的影響。

PageHelper 的實現原理主要依賴於攔截器技術和反射機制,通過攔截查詢語句並動態生成分頁語句,實現了簡單、高效、通用的分頁功能。具體原始碼在下圖的類中,非常容易看懂。

明白了PageHelper的工作原理後,反覆檢查程式碼,都沒有呼叫過startPagedebug檢視ThreadLocal中也沒有分頁資訊啊,懵逼中。那我看看別人寫的新增分頁引數的程式碼吧,不看不知道,一看嚇一跳。

原來有位“可愛”的同事竟然在查詢後,加了一個分頁,就是把分頁資訊放到執行緒的ThreadLocal中。

那大家是不是有疑問,丁是丁,矛是矛,你的執行緒關我何事?這就要說到我們的tomcat了。

Tomcat請求流程

其實這就涉及到我們的tomcat相關知識了,我們一個瀏覽器發一個介面請求,經過我們的tomcat的,究竟是一個什麼樣的流程呢?

  • 使用者端傳送HTTP請求到Tomcat伺服器。
  • TomcatHTTP聯結器(Connector)接收到請求,將連線請求交給執行緒池Executor處理,解析它,然後將請求轉發給對應的Web應用程式。
  • Tomcat的Web應用程式容器(Container)接收到請求,根據請求的URL找到對應的Servlet

關於tomcat中使用執行緒池提交瀏覽器的連線請求的原始碼如下:

從而得知,你的連線請求是從執行緒池從拿的,而拿到的這個執行緒恰好是一個“髒執行緒”,在ThreadLocal中放了分頁資訊,導致你這邊出現問題。

總結

後來追問了同事具體原因,才發現是粗心導致的。有些bug總是出現的莫名其妙,就像生活一樣。所以關鍵的是我們在使用一些開源框架的時候一定要掌握底層實現的原理、核心的機制,這樣才能夠在解決一些問題的時候有據可循。

以上就是PageHelper引發的幽靈資料問題解析的詳細內容,更多關於PageHelper幽靈資料的資料請關注it145.com其它相關文章!


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