国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看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

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 精品久久久久久亚洲精品 | 国产电影一区二区三区图片 | 黄色网址视频大全 | 亚洲字幕网 | 欧美视频在线免费 | www久久久| 亚洲精品视频一区二区三区 | 久久人人爽人人爽人人片av不 | 亚洲精品一区二区三区蜜桃下载 | 日韩精品在线视频 | 欧美精品在线一区二区三区 | 午夜影院免费 | 久久久成人免费 | 亚洲专区 变态 另类 | 国产精品一区二区三区在线播放 | 亚洲视频观看 | 午夜视频网站 | 九九精品在线 | 亚洲国产中文字幕 | 国产中文字幕亚洲 | 午夜视频网站 | 国产精品毛片在线 | 成人精品视频在线观看 | 久久久久久久一区 | 欧美在线观看黄 | 午夜av电影 | 日本一区免费 | 欧美日韩国产中文 | 羞羞视频在线免费观看 | 婷婷五月在线视频 | 日韩不卡一区二区三区 | 日韩色av | 国产成人精品一区二区三区四区 | 涩涩视频观看 | 欧美色综合天天久久综合精品 | 国产黄色在线网站 | 久久精品影视 | 日韩成人中文字幕 | 国产精品一区二区不卡 | 亚洲成人免费在线 | 日韩在线一区二区 |