JDBC 再升級 — 使用p6spy監控SQL執行結果

在開發專案時,我們通常會很在意 SQL 的執行狀況,像是

  • 想知道 SQL 執行的效能如何
  • 實際在資料庫執行的 SQL 內容為何
    • 使用 JDBC prepared statement時 “?”參數的內容
    • OR mapping 工具最後產生的 SQL 語句內容

當然我們也可以自己加幾行程式碼來取得這些資訊,但大家可以想一想,這些用來純粹取得 SQL 執行內容的程式碼,無關任何業務邏輯,這樣的程式碼放在專案裡真的好嗎?修改幅度不大的話,或許可以這麼做。但如果是有點規模的專案,光是加這些監控的程式碼就是一項很耗費時間的工作,再加上一個不小心動到原本正常執行的程式,那更是得不償失!

今天要介紹一個工具:p6spy,只要透過幾個簡單設定,就可以觀察所有 SQL 的執行狀況,而且移除也很容易,非常適合專案在開發階段時使用!

  1. 請 clone 以下專案
    https://github.com/kennyliao1982/demo-p6spy
  2. 匯入 Eclipse 之後,執行 mvn  package,確保需要的 dependency 都有抓到
  3. 執行 src/main/java 底下的 com.appx.demo.p6spy.App.java
  4. 觀察 console

大家可以看到 log 的上半部記載了 SQL 執行狀況,log的格式如下:(以”|”分隔)
執行當下時間 | 執行耗費時間 | log種類 | connection id | prepared statement SQL語句
實際執行的SQL語句

這次的測試一樣使用了H2 database + Hikari connection pool,主要執行流程如下:
(可參考App.java 的 main 方法)

  1. 啟動資料庫
  2. 建立 DataSource,新建 user table,新增幾筆 user 資料
  3. 查詢所有 user資料
  4. 關閉資料庫

大部分的操作都和之前在示範 connection pool 時一樣,究竟在哪裡用到 p6spy 呢?答案在 App.java 第61行

對,程式碼的異動,就只有這麼一行!這一行只是把原本建立好的 HikariDataSource 物件用 p6spy 提供的 P6DataSource 包裝起來,後續的參數一律使用 P6DataSource,這樣就達到 SQL logging 的效果了!( log 輸出格式的設定可以參考 src/main/resources/spy.properties,基本上都用預設值)

P6DataSource 針對原有 DataSource 作了包裝並加上 logging 機制,實現了 design pattern 中的 decorator pattern (另一個典型例子就是 Java IO 的 BufferedReader )

我們這個案例是手動建立資料庫連線,所以使用 p6spy 需要動一點程式碼,如果是在使用了 framework 的架構下,基本上資料庫連線都是由 framework 讀取設定後負責建立的,這種情況下要使用 p6spy 只需動動設定檔就好,對於程式碼來說沒有任何影響,之後要移除也是非常容易!

JDBC 再升級 — connection pool 牛刀小試

這回要透過一個簡單的例子,讓大家實際感受使用了 connection pool 前後的差異!

  1. 把這個專案 clone 下來
    https://github.com/kennyliao1982/demo-connection-pooling
  2. 在專案根目錄下執行  mvn test
  3. 從console log 就可以看出測試的數據囉!

    *測試說明:測試方式為開關 connection 5000 次,並計算其平均以及全部所花費的時間 (單位是毫秒),由上圖可看出

    • 最慢: NoConnectionPoolingTest,開關一次 connection要 7.106 毫秒,跑完5000回合需要35530毫秒
    • 最快: HikariConnectionPoolingTest,開關一次 connection要 0.017 毫秒,跑完5000回合需要85毫秒

看到這裡,相信大家已經深刻的體會到 connection pool 對於效能優化帶來多麼大的幫助。 connection pool 在市面上有不少團隊推出自己的實作: c3p0, dbcp2, BoneCP, tomcat, vibur, HikariCP…等等,經由上面的簡單測試可以稍微比較一下哪家的效能比較好


如果對於上面測試的程式有興趣的同學,可參考以下說明:

  • 使用了快速、輕巧的資料庫H2 database,可以內嵌在應用程式裡,方便執行測試
  • 基於JUnit,可參考 AbstractConnectionTest.java
    • 在@BeforeClass, @AfterClass 裡啟動/關閉H2資料庫
    • 標註了 @Test的 testOpenCloseConnections 為主要測試流程
    • abstract method initDataSource() 由子類別自行實作,這是 design pattern 的 Template (method) pattern

JDBC 再升級 — 使用 connection pool

我們在學習了基本JDBC的操作之後, 如果要更進一步在正式專案使用JDBC,我自己過去的專案經驗是100%都會使用 connection pool 來處理資料庫連線。雖然這已經是一種很普遍的作法,但從學習的角度來看,我們必須知其然,也知其所以然!

Continue reading →