激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 利用JDBC的PrepareStatement打印真實SQL的方法詳解

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

2020-12-06 15:06sp42a Java教程

PreparedStatement是預編譯的,對于批量處理可以大大提高效率. 也叫JDBC存儲過程,下面這篇文章主要給大家介紹了關于利用JDBC的PrepareStatement打印真實SQL的方法,需要的朋友可以參考借鑒,下面來一起看看吧。

前言

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

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

方法如下:

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * 查詢單個結果,保存為 Map<String, Object> 結構。如果查詢不到任何數據返回 null。
 *
 * @param conn
 *   數據庫連接對象
 * @param sql
 *   SQL 語句,可以帶有 ? 的占位符
 * @param params
 *   插入到 SQL 中的參數,可單個可多個可不填
 * @return Map<String, Object> 結構的結果。如果查詢不到任何數據返回 null。
 */
public static Map<String, Object> query(Connection conn, String sql, Object... params) {
 Map<String, Object> map = null;
 printRealSql(sql, params); // 打印真實 SQL 的函數
  
 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;
}

值得注意該函數里面:

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

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

printRealSql 函數源碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * 在開發過程,SQL語句有可能寫錯,如果能把運行時出錯的 SQL 語句直接打印出來,那對排錯非常方便,因為其可以直接拷貝到數據庫客戶端進行調試。
 *
 * @param sql
 *   SQL 語句,可以帶有 ? 的占位符
 * @param params
 *   插入到 SQL 中的參數,可單個可多個可不填
 * @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 語句中的占位符與參數個數不匹配。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;
}
 
/**
 * ? 和參數的實際個數是否匹配
 *
 * @param sql
 *   SQL 語句,可以帶有 ? 的占位符
 * @param params
 *   插入到 SQL 中的參數,可單個可多個可不填
 * @return true 表示為 ? 和參數的實際個數匹配
 */
private static boolean match(String sql, Object[] params) {
 if(params == null || params.length == 0) return true; // 沒有參數,完整輸出
  
 Matcher m = Pattern.compile("(\\?)").matcher(sql);
 int count = 0;
 while (m.find()) {
  count++;
 }
  
 return count == params.length;
}

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

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

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

總結

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

原文鏈接:http://blog.csdn.net/zhangxin09/article/details/70187712

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: xnxx 日本19| 国产亚洲综合一区二区 | 黄在线观看在线播放720p | 99精品在线视频观看 | 369看片你懂的小视频在线观看 | 色中色在线视频 | 久久精品无码一区二区日韩av | 久久国产28| 日韩激情一区二区三区 | 久操免费在线视频 | 日本综合久久 | 久久精品国产清自在天天线 | av色偷偷 | 亚洲午夜国产 | 国产美女爽到喷白浆的 | 爱唯侦察 国产合集 亚洲 | 色诱亚洲精品久久久久久 | 91av大片 | 欧美性猛交xxx乱大交3蜜桃 | 国产亚洲欧美一区久久久在 | 国产一区二区视频精品 | 一本色道久久综合狠狠躁篇适合什么人看 | 久久影院午夜 | 亚洲一区成人 | 亚洲精品7777 | 欧美大电影免费观看 | 亚洲影视在线 | 色综合中文字幕 | 偷偷操偷偷操 | 黄色毛片观看 | 一级黄色欧美 | 日韩一级成人 | 玩偶姐姐 在线观看 | 精品亚洲午夜久久久久91 | 久国久产久精永久网页 | 欧美性受xxxxxx黑人xyx性爽 | 日本在线视频免费观看 | 夜添久久精品亚洲国产精品 | 精品91av| 久久色播 | 久久久久女人精品毛片九一 |