JDBC 查詢日志變得簡單
JDBC java.sql.PreparedStatement接口的簡單擴展可以使查詢記錄更少犯錯,同時整理您的代碼。在本文中,IBM電子商務顧問Jens Wyke向您介紹如何應用基本的封裝技術(“通過封裝來實現擴展”也稱為Decorator設計模式)來獲得最滿意的結果。
在大多數情況下,JDBC PreparedStatements
使執行數據庫查詢更簡便并可以顯著提升您整體應用程序的性能。當談到日志查詢語句時 PreparedStatement
接口就顯得有些不足了。 PreparedStatement
的優勢在于其可變性,但是一個好的日志條目必須正確描述如何將SQL發送到數據庫,它將密切關注用實際的參數值來替換所有參數占位符。雖然有多種方法可以解決這一難題,但沒有任何一種易于大規模實施并且大部分將擾亂您的程序代碼。
在本文中,您將了解到如何擴展JDBC PreparedStatement
接口來進行查詢日志。 LoggableStatement
類實現 PreparedStatement
接口,但添加用于獲得查詢字符串的方法,使用一種適用于記錄的格式。使用 LoggableStatement
類可以減少日志代碼中發生錯誤的幾率,生成簡單且易于管理的代碼。
注意:本文假設您有豐富的JDBC和 PreparedStatement
類經驗。
表1介紹了數據庫查詢時通常是如何使用 PreparedStatement
(雖然忽略了初始化和錯誤處理)。在本文中,我們將使用SQL query SELECT
做為例子,但討論使用其它類型的SQL語句,如 DELETE
、 UPDATE
和 INSERT
。
表1:一個典型的SQL數據庫查詢
|
表1中一個好的查詢日志條目看起來應與下面有幾分類似:
|
下面是查詢的日志代碼的一個例子。注意:表1中的問號已經被每個參數的值替換。
|
一種更好的方法是創建方法,我們稱之為 replaceFirstQuestionMark
,它讀取查詢字符串并用參數值替換問號,如表2所示。這類方法的使用無需創建復制的字符串來描述SQL語句。
表 2:使用replaceFirstQuestionMark來進行字符串替換
|
雖然這些解決方案都易于實施,但沒有一種是完美的。問題是在更改SQL模板的同時也必須更改日志代碼。您將在某一點上犯錯幾乎是不可避免的。查詢將更改但您忘記了更新日志代碼,您將結束與將發送到數據庫的查詢不匹配的日志條目 -- 調試惡夢。
我們真正需要的是一種使我們能夠一次性使用每個參數變量(在我們的實例中為 fooValue
和 barValue
)的設計方案。我們希望有一種方法,它使我們能夠獲得查詢字符串,并用實際的參數值替換參數占位符。由于 java.sql.PreparedStatement
沒有此類方法,我們必須自己實現。
![]() ![]() |
![]()
|
我們的 PreparedStatement
定制實施將做為圍繞JDBC驅動器提供的“真實語句(real statement)”的封裝器(Wrapper)。封裝器語句將轉發所有方法調用(例如 setLong(int, long)
和 setString(int,String)
) 到“真實語句”。在這樣做之前它將保存相關的參數值,從而它們可以用于生成日志輸出結果。
表3介紹了 LoggableStatement
類如何實現 java.sql.PreparedStatement
,以及它如何使用JDBC連接和SQL模板作為輸入來構建。
表3:LoggableStatement實現java.sql.PreparedStatement
|
![]() ![]() |
![]()
|
表4介紹了 LoggableStatement
如何向 saveQueryParamValue()
方法添加一個調用,以及在方法 setLong
和 setString
的“真實語句”上調用相應的方法。我們采用與用于參數設置的所有方法(例如 setChar
、 setLong
、 setRef
和 setObj
)相同的方式來增加 saveQueryParamValue()
調用。表4還顯示了在不調用 saveQueryParamValue()
的情況下如何封裝方法 executeQuery
,因為它不是一個“參數設置”方法。
表4:LoggableStatement 方法
|
表5中顯示了 saveQueryParamValue()
方法。它把每個參數值轉換成 String
表示,保存以便 getQueryString
方法日后使用。缺省情況下,一個對象使用其 toString
方法將被轉換成 String
,但如果對象是 String
或 Date
,它將用單引號('')表示。 getQueryString()
方法使您能夠從日志復制大多數查詢并進行粘貼,無需修改交互式SQL處理器就可進行測試和調試。您可以根據需要修訂該方法來轉換其它類的參數值。
表5:saveQueryParamValue()方法
|
當我們使用標準方法來設置所有參數時,我們在 LoggableStatement
中簡單調用 getQueryString()
方法來獲得查詢字符串。所有問號都將被真正的參數值替換,它準備輸出到我們選定的日志目的地。
![]() ![]() |
![]()
|
表6顯示如何更改表1和表2中的代碼來使用 LoggableStatement
。將 LoggableStatement
引入到我們的應用程序代碼中可以解決復制的參數變量問題。如果改變了SQL模板,我們只需更新 PreparedStatement
上的參數設置調用(例如添加一個 pstmt.setString(3,"new-param-value")
)。這一更改將在日志輸出結果中反映出,無需任何記錄代碼的手工更新。
表6:使用LoggableStatement 
|
![]() ![]() |
![]()
|
使用本文介紹的非常簡單的步驟,您可以為查詢記錄擴展JDBC PreparedStatement
接口。我們在此處使用的技術可以被視為“通過封裝來實現擴展”,或作為Decorator設計模式的一個實例(見 參考資料)。通過封裝來實現擴展在當您必須擴展API但subclassing不是一項可選功能時極其有用。
posted on 2006-08-24 17:50 Binary 閱讀(248) 評論(0) 編輯 收藏 所屬分類: j2se