中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JDBC查詢日志記錄的方法有哪些

發布時間:2022-02-28 16:42:04 來源:億速云 閱讀:749 作者:iii 欄目:開發技術

今天小編給大家分享一下JDBC查詢日志記錄的方法有哪些的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

在大多數情況下,JDBCPreparedStatement使執行數據庫查詢變得更加容易,并且可以顯著提高你的整體應用程序性能。但是PreparedStatement當涉及到記錄查詢語句時,該接口就不夠用了。盡管 aPreparedStatement的優勢在于其可變性,但一個好的日志條目必須準確描述發送到數據庫的 SQL 在所有參數占位符已被實際參數值替換后的外觀。盡管有多種方法可以解決這個難題,但沒有一種方法可以輕松大規模實現,而且大多數方法都會使你的代碼變得混亂。

在本文中,你將學習如何擴展 JDBCPreparedStatement接口以進行查詢日志記錄。雖然LoggableStatement類實現的PreparedStatement接口,但增加了在適合于記錄的格式獲得查詢字符串的方法。使用LoggableStatement該類既可以減少日志代碼中的錯誤發生率,又可以隨著時間的推移生成更整潔、更易于管理的代碼。

請注意,本文假設你之前有使用 JDBC 和PreparedStatement類的經驗。

典型的查詢記錄解決方案

清單 1 說明了PreparedStatement在進行數據庫查詢時通常如何使用 a(盡管省略了初始化和錯誤處理)。我們將使用SQL查詢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 模板進行更改時,日志記錄代碼也必須更改。在某些時候你會犯錯誤幾乎是不可避免的。查詢將被更改,但您將忘記更新日志記錄代碼,并且你最終會得到與發送到數據庫的查詢不匹配的日志條目——這是調試噩夢。

我們真正需要的是一個設計,讓我們使用的每個參數變量(fooValuebarValue在我們的例子)只有一次。我們想要一種方法,它可以讓我們獲取參數占位符替換為實際值的查詢字符串。因為java.sql.PreparedStatement沒有這樣的方法,我們必須自己實現一個。

自定義解決方案

我們的自定義實現PreparedStatement將充當 JDBC 驅動程序提供的“真實語句”的包裝器。包裝器語句會將所有方法調用(例如,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和 setStringreal語句上調用相應的方法。saveQueryParamValue()調用以類似的方式添加到用于參數設置的所有方法(例如setCharsetLongsetRef、 和setObj)。清單 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();
   }

saveQueryParamValue()方法如清單 5 所示。它將每個參數值轉換為一種String表示形式,并將其保存以供該getQueryString方法以后使用。默認情況下,對象將String使用其toString方法轉換為 a ,但如果對象是 aStringa 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);
 }

當使用標準方法設置所有參數時,我們只需調用我們的getQueryString()方法LoggableStatement來獲取查詢字符串。所有問號都將替換為實際參數值,這些值已準備好輸出到我們選擇的日志記錄目的地。

使用 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查詢日志記錄的方法有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

北海市| 曲阜市| 永和县| 浑源县| 鹤峰县| 尼玛县| 修文县| 鹤庆县| 洪雅县| 佛坪县| 陆丰市| 长泰县| 潞西市| 阳谷县| 清涧县| 如皋市| 昌吉市| 辉县市| 道孚县| 宁波市| 措美县| 高尔夫| 鄂托克前旗| 咸丰县| 徐闻县| 临沧市| 台北市| 克东县| 万年县| 武城县| 汝阳县| 饶河县| 漳浦县| 宜兴市| 铁岭市| 阿拉善左旗| 天长市| 红桥区| 紫阳县| 清丰县| 铁岭县|