国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

讓JDBC查詢日志變得簡單

2024-07-21 02:08:00
字體:
來源:轉載
供稿:網友

    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數據庫查詢


string sql = "select foo, bar from foobar where foo < ? and bar = ?"; string foovalue = new long(99); string barvalue = "christmas"; connection conn = datasource.getconnection(); preparedstatement pstmt = conn.preparestatement(sql); pstmt.setlong(1,foovalue); pstmt.setstring(2,barvalue); resultset rs = pstmt.executequery(); // parse result...


  表1中一個好的查詢日志條目看起來應與下面有幾分類似:


executing query: select foo,bar from foobar where foo < 99 and bar='christmas'


  下面是查詢的日志代碼的一個例子。注意:表1中的問號已經被每個參數的值替換。


system.out.println("executing query:  select foo, bar from foobar where foo< "+foovalue+" and bar = '+barvalue+"'")


  一種更好的方法是創建方法,我們稱之為replacefirstquestionmark,它讀取查詢字符串并用參數值替換問號,如表2所示。這類方法的使用無需創建復制的字符串來描述sql語句。

  表 2:使用replacefirstquestionmark來進行字符串替換


// listing 1 goes here sql = replacefirstquestionmark(sql, foovalue); sql = replacefirstquestionmark(sql, barvalue); system.out.println("executing query: "+sql);


  雖然這些解決方案都易于實施,但沒有一種是完美的。問題是在更改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


public class loggablestatement implements java.sql.preparedstatement { // used for storing parameter values needed // for producing log private arraylist parametervalues; // the query string with question marks as // parameter placeholders private string sqltemplate; // a statement created from a real database // connection private preparedstatement wrappedstatement; public loggablestatement(connection connection, string sql) throws sqlexception { // use connection to make a prepared statement wrappedstatement = connection.preparestatement(sql); sqltemplate = sql; parametervalues = new arraylist(); } }


  loggablestatement如何工作

  表4介紹了loggablestatement如何向savequeryparamvalue()方法添加一個調用,以及在方法setlong和setstring的“真實語句”上調用相應的方法。我們采用與用于參數設置的所有方法(例如setchar、setlong、setref和setobj)相同的方式來增加savequeryparamvalue()調用。表4還顯示了在不調用savequeryparamvalue()的情況下如何封裝方法executequery,因為它不是一個“參數設置”方法。

  表4:loggablestatement 方法


public void setlong(int parameterindex, long x) throws java.sql.sqlexception { wrappedstatement.setlong(parameterindex, x); savequeryparamvalue(parameterindex, new long(x)); } public void setstring(int parameterindex, string x) throws java.sql.sqlexception { wrappedstatement.setstring(parameterindex, x); savequeryparamvalue(parameterindex, x); } public resultset executequery() throws java.sql.sqlexception { return wrappedstatement.executequery(); }


  表5中顯示了savequeryparamvalue()方法。它把每個參數值轉換成string表示,保存以便getquerystring方法日后使用。缺省情況下,一個對象使用其 tostring方法將被轉換成string,但如果對象是string或date,它將用單引號('')表示。getquerystring()方法使您能夠從日志復制大多數查詢并進行粘貼,無需修改交互式sql處理器就可進行測試和調試。您可以根據需要修訂該方法來轉換其它類的參數值。

  表5:savequeryparamvalue()方法


private void savequeryparamvalue(int position, object obj) { string strvalue; if (obj instanceof string || obj instanceof date) { // if we have a string, include '' in the saved value strvalue = "'" + obj + "'"; } else { if (obj == null) { // convert null to the string null strvalue = "null"; } else { // unknown object (includes all numbers), just call tostring strvalue = obj.tostring(); } } // if we are setting a position larger than current size of // parametervalues, first make it larger while (position >= parametervalues.size()) { parametervalues.add(null); } // save the parameter parametervalues.set(position, strvalue); }


  當我們使用標準方法來設置所有參數時,我們在loggablestatement中簡單調用getquerystring()方法來獲得查詢字符串。所有問號都將被真正的參數值替換,它準備輸出到我們選定的日志目的地。

  使用loggablestatement

  表6顯示如何更改表1和表2中的代碼來使用 loggablestatement。將loggablestatement引入到我們的應用程序代碼中可以解決復制的參數變量問題。如果改變了sql模板,我們只需更新preparedstatement上的參數設置調用(例如添加一個pstmt.setstring(3,"new-param-value"))。這一更改將在日志輸出結果中反映出,無需任何記錄代碼的手工更新。

  表6:使用loggablestatement

  
string sql = "select foo, bar from foobar where foo < ? and bar = ?"; long foovalue = 99; string barvalue = "christmas"; connection conn = datasource.getconnection(); preparedstatement pstmt; if(logenabled) // use a switch to toggle logging. pstmt = new loggablestatement(conn,sql); else pstmt = conn.preparestatement(sql); pstmt.setlong(1,foovalue); pstmt.setstring(2,barvalue); if(logenabled) system.out.println("executing query: "+ ((loggablestatement)pstmt).getquerystring()); resultset rs = pstmt.executequery();


  結束語

  使用本文介紹的非常簡單的步驟,您可以為查詢記錄擴展jdbc preparedstatement接口。我們在此處使用的技術可以被視為“通過封裝來實現擴展”,或作為decorator設計模式的一個實例(見參考資料)。通過封裝來實現擴展在當您必須擴展api但subclassing不是一項可選功能時極其有用。

  您將在參考資料部分找到loggablestatement類的源代碼。您可以按原樣使用它,或者進行定制以滿足您的數據庫應用程序的特殊需求。

  參考資料

  ◆ 下載loggablestatement類的源代碼 。

  ◆ 您將在roman vichr的提示和技巧:jdbc 提示 (developerworks, 2002年10月)中找到使用preparedstatements的簡要介紹.

  ◆ lennart jorelid的“use jdbc for industrial-strength performance ”(developerworks,2000年1月)是一篇不錯的在jdbc中設計模式的兩部分介紹性文章。

  ◆ josh heidebrecht撰寫的“jdbc 3.0新特性 ”(developerworks,2001年7月)提供jdbc 3.0的概述。

  ◆ 您可以從java.sun.com 下載java platform, standard edition和jdbc 3.0 api規范。

  ◆ david gallardo的“java設計模式101 ”(developerworks,2002年1月)是gang of four模板不錯的介紹。

  ◆ paul monday的“ java設計模式 201”(developerworks,2002年4月)為高級學員提供了java設計模式更具概念性的說明。

  ◆ vince huston的 design patterns site 是另外一個了解設計模式不錯的資源。

  ◆ brian goetz的“java 理論與實踐:性能管理 — 您有規劃嗎? ” (developerworks,2003年3月)闡述了一些您可以實施用來提升java應用程序整體性能的措施。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 蒲城县| 济源市| 南岸区| 当雄县| 探索| 昭通市| 晋城| 新沂市| 通州市| 申扎县| 五大连池市| 云霄县| 张北县| 泗阳县| 海林市| 鄂尔多斯市| 腾冲县| 崇阳县| 自治县| 西城区| 岐山县| 成武县| 临猗县| 东平县| 交口县| 新化县| 景泰县| 烟台市| 江孜县| 常熟市| 友谊县| 沭阳县| 江西省| 金华市| 鞍山市| 林芝县| 新疆| 法库县| 龙陵县| 巨野县| 大方县|