欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

利用JDBC的PrepareStatement打印真實SQL的方法詳解

 更新時間:2017年07月25日 09:06:38   作者:sp42a  
PreparedStatement是預編譯的,對于批量處理可以大大提高效率. 也叫JDBC存儲過程,下面這篇文章主要給大家介紹了關于利用JDBC的PrepareStatement打印真實SQL的方法,需要的朋友可以參考借鑒,下面來一起看看吧。

前言

本文主要給大家介紹了關于利用JDBC的PrepareStatement打印真實SQL的相關內容,分享出來供大家參考學習,下面來一起看看詳細的介紹:

我們知道,JDBC 的 PrepareStatement 優(yōu)點多多,通常都是推薦使用 PrepareStatement 而不是其基類 Statment。PrepareStatement 支持 ? 占位符,可以將參數(shù)按照類型轉自動換為真實的值。既然這一過程是自動的,封裝在 JDBC 內部的,那么我們外部就不得而知目標的 SQL 最終生成怎么樣——于是在調試過程中便有一個打印 SQL 的問題。我們對 PrepareStatement 傳入 SQL 語句,如 SELECT * FROM table WHERE id = ?,然后我們傳入對應的 id 參數(shù),假設是 id = 10,那怎么把得到參數(shù)的 SELECT * FROM table WHERE id =  12 結果完整地得出來呢?——這便是本文所要探討的問題。下面話不多說了,來一起看看詳細的介紹:

方法如下:

首先,我們看看典型的一個 PrepareStatement 調用方法,如下一個函數(shù),

/** 
 * 查詢單個結果,保存為 Map<String, Object> 結構。如果查詢不到任何數(shù)據(jù)返回 null。 
 * 
 * @param conn 
 *   數(shù)據(jù)庫連接對象 
 * @param sql 
 *   SQL 語句,可以帶有 ? 的占位符 
 * @param params 
 *   插入到 SQL 中的參數(shù),可單個可多個可不填 
 * @return Map<String, Object> 結構的結果。如果查詢不到任何數(shù)據(jù)返回 null。 
 */ 
public static Map<String, Object> query(Connection conn, String sql, Object... params) { 
 Map<String, Object> map = null; 
 printRealSql(sql, params); // 打印真實 SQL 的函數(shù) 
  
 try (PreparedStatement ps = conn.prepareStatement(sql);) { 
  if(params != null) 
   for (int i = 0; i < params.length; i++) 
    ps.setObject(i + 1, params[i]); 
   
  try (ResultSet rs = ps.executeQuery();) { 
   if (rs.isBeforeFirst()) { 
    map = getResultMap(rs); 
   } else { 
    LOGGER.info("查詢 SQL:{0} 沒有符合的記錄!", sql); 
   } 
  } 
 } catch (SQLException e) { 
  LOGGER.warning(e); 
 } 
  
 return map; 
} 

值得注意該函數(shù)里面:

printRealSql(sql, params); // 打印真實 SQL 的函數(shù) 

其參數(shù)一 sql 就是類似 SELECT * FROM table WHERE id = ? 的語句,參數(shù)二 params 為 Object... params 的參數(shù)列表,可以是任意類似的合法 SQL 值。最后,通過 printRealSql 函數(shù)最終得出形如 SELECT * FROM table WHERE id =  12 的結果。

printRealSql 函數(shù)源碼如下:

/** 
 * 在開發(fā)過程,SQL語句有可能寫錯,如果能把運行時出錯的 SQL 語句直接打印出來,那對排錯非常方便,因為其可以直接拷貝到數(shù)據(jù)庫客戶端進行調試。 
 * 
 * @param sql 
 *   SQL 語句,可以帶有 ? 的占位符 
 * @param params 
 *   插入到 SQL 中的參數(shù),可單個可多個可不填 
 * @return 實際 sql 語句 
 */ 
public static String printRealSql(String sql, Object[] params) { 
 if(params == null || params.length == 0) { 
  LOGGER.info("The SQL is------------>\n" + sql); 
  return sql; 
 } 
  
 if (!match(sql, params)) { 
  LOGGER.info("SQL 語句中的占位符與參數(shù)個數(shù)不匹配。SQL:" + sql); 
  return null; 
 } 
 
 int cols = params.length; 
 Object[] values = new Object[cols]; 
 System.arraycopy(params, 0, values, 0, cols); 
 
 for (int i = 0; i < cols; i++) { 
  Object value = values[i]; 
  if (value instanceof Date) { 
   values[i] = "'" + value + "'"; 
  } else if (value instanceof String) { 
   values[i] = "'" + value + "'"; 
  } else if (value instanceof Boolean) { 
   values[i] = (Boolean) value ? 1 : 0; 
  } 
 } 
  
 String statement = String.format(sql.replaceAll("\\?", "%s"), values); 
 
 LOGGER.info("The SQL is------------>\n" + statement); 
 
 ConnectionMgr.addSql(statement); // 用來保存日志 
  
 return statement; 
} 
 
/** 
 * ? 和參數(shù)的實際個數(shù)是否匹配 
 * 
 * @param sql 
 *   SQL 語句,可以帶有 ? 的占位符 
 * @param params 
 *   插入到 SQL 中的參數(shù),可單個可多個可不填 
 * @return true 表示為 ? 和參數(shù)的實際個數(shù)匹配 
 */ 
private static boolean match(String sql, Object[] params) { 
 if(params == null || params.length == 0) return true; // 沒有參數(shù),完整輸出 
  
 Matcher m = Pattern.compile("(\\?)").matcher(sql); 
 int count = 0; 
 while (m.find()) { 
  count++; 
 } 
  
 return count == params.length; 
} 

可見,上述思路是非常簡單的,——有多少個 ? 占位符,就要求有多少個參數(shù),然后一一對照填入(數(shù)組)。match 函數(shù)會檢查第一個步驟,檢查個數(shù)是否匹配,否則會返回“SQL 語句中的占位符與參數(shù)個數(shù)不匹配”的提示;然后,參數(shù)的值會被轉換為符合 SQL 值所要求的類型;最后,就是將 SQL 一一填入,——此處使用了一個字符串的技巧,先把 ? 字符通通轉換為 %s,——那是 String.format 可識別的占位符,如此再傳入 Object[] 參數(shù)列表,即可得出我們期待的 SQL 結果。

我們不能保證那 SQL 可以直接放到數(shù)據(jù)庫中被解析。因為我們的初衷只是把 SQL 打印出來,務求更近一步讓程序員在開發(fā)階段看到 SQL 是怎么樣子的,而且不是一堆 ?、?……,這樣會顯得更符合真實情形一點。

PrepareStatement 內部源碼肯定有這一步驟或者某個變量是表示那個真實 SQL 的,——只是沒有暴露出來。如果有,那么對程序員會更友好一些。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • idea新建maven項目沒有src目錄的操作方法

    idea新建maven項目沒有src目錄的操作方法

    這篇文章主要介紹了idea新建maven項目沒有src目錄的兩種操作方法,需要的朋友可以參考下
    2018-03-03
  • java生成excel報表文件示例

    java生成excel報表文件示例

    本篇文章主要介紹了java生成excel報表文件示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • Java8中對泛型目標類型推斷方法的改進

    Java8中對泛型目標類型推斷方法的改進

    這篇文章主要介紹了Java8中對泛型目標類型推斷方法的改進,需要的朋友可以參考下
    2014-06-06
  • Java源碼解析重寫鎖的設計結構和細節(jié)

    Java源碼解析重寫鎖的設計結構和細節(jié)

    這篇文章主要為大家介紹了Java源碼解析重寫鎖的設計結構和細節(jié),這小節(jié)我們以共享鎖作為案列,自定義一個共享鎖。有需要的朋友可以借鑒參考下
    2022-03-03
  • java案例實戰(zhàn)之字符串轉換為二進制

    java案例實戰(zhàn)之字符串轉換為二進制

    最近遇到個需求,要求編寫一個程序,從鍵盤錄入一個字符串,將字符串轉換為二進制數(shù),下面這篇文章主要給大家介紹了關于java字符串轉換為二進制的相關資料,需要的朋友可以參考下
    2023-06-06
  • Java使用鎖解決銀行取錢問題實例分析

    Java使用鎖解決銀行取錢問題實例分析

    這篇文章主要介紹了Java使用鎖解決銀行取錢問題,結合實例形式分析了java線程同步與鎖機制相關原理及操作注意事項,需要的朋友可以參考下
    2019-08-08
  • Java中支持可變參數(shù)詳解

    Java中支持可變參數(shù)詳解

    那個可變參數(shù)的就是個數(shù)組,你傳多少個參數(shù)都被放到那個數(shù)組里面。這樣方便了程序員,因為如果不確定要傳的參數(shù)的個數(shù)的話,我們要寫帶1個參數(shù)的,帶2個參數(shù),帶3個參數(shù)的,這樣很麻煩。 該進后的這個方法,我們只要寫一個函數(shù)就好,可以傳任意個參數(shù)。
    2015-05-05
  • java語法糖之jdk迭代的新特性匯總

    java語法糖之jdk迭代的新特性匯總

    什么是語法糖?泛型、自動裝箱拆箱、變長參數(shù)、增強for循環(huán)、switch字符類型、lambda表達式等,這些其實都是語法糖。這篇文章主要給大家介紹了關于java語法糖之jdk迭代的新特性的相關資料,需要的朋友可以參考下
    2021-05-05
  • java的Guava工具包介紹

    java的Guava工具包介紹

    Java開發(fā)的同學應該都使用或者聽說過Google提供的Guava工具包。日常使用最多的肯定是集合相關的工具類,還有Guava cache,除了這些之外Guava還提供了很多有用的功能,鑒于日常想用的時候找不到,這里就梳理一下Guava中那些好用的工具類,想優(yōu)化代碼的時候不妨過來看看
    2021-04-04
  • SSM項目實現(xiàn)短信驗證碼登錄功能的示例代碼

    SSM項目實現(xiàn)短信驗證碼登錄功能的示例代碼

    這篇文章主要為大家分享了在SSM項目中實現(xiàn)短信驗證碼登錄功能的示例代碼,文中的實現(xiàn)步驟講解詳細,感興趣的小伙伴可以跟隨小編一起動手嘗試一下
    2022-05-05

最新評論