最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用JDBC的PrepareStatement打印真實(shí)SQL的方法詳解

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

前言

本文主要給大家介紹了關(guān)于利用JDBC的PrepareStatement打印真實(shí)SQL的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面來(lái)一起看看詳細(xì)的介紹:

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

方法如下:

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

/** 
 * 查詢單個(gè)結(jié)果,保存為 Map<String, Object> 結(jié)構(gòu)。如果查詢不到任何數(shù)據(jù)返回 null。 
 * 
 * @param conn 
 *   數(shù)據(jù)庫(kù)連接對(duì)象 
 * @param sql 
 *   SQL 語(yǔ)句,可以帶有 ? 的占位符 
 * @param params 
 *   插入到 SQL 中的參數(shù),可單個(gè)可多個(gè)可不填 
 * @return Map<String, Object> 結(jié)構(gòu)的結(jié)果。如果查詢不到任何數(shù)據(jù)返回 null。 
 */ 
public static Map<String, Object> query(Connection conn, String sql, Object... params) { 
 Map<String, Object> map = null; 
 printRealSql(sql, params); // 打印真實(shí) 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} 沒(méi)有符合的記錄!", sql); 
   } 
  } 
 } catch (SQLException e) { 
  LOGGER.warning(e); 
 } 
  
 return map; 
} 

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

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

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

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

/** 
 * 在開發(fā)過(guò)程,SQL語(yǔ)句有可能寫錯(cuò),如果能把運(yùn)行時(shí)出錯(cuò)的 SQL 語(yǔ)句直接打印出來(lái),那對(duì)排錯(cuò)非常方便,因?yàn)槠淇梢灾苯涌截惖綌?shù)據(jù)庫(kù)客戶端進(jìn)行調(diào)試。 
 * 
 * @param sql 
 *   SQL 語(yǔ)句,可以帶有 ? 的占位符 
 * @param params 
 *   插入到 SQL 中的參數(shù),可單個(gè)可多個(gè)可不填 
 * @return 實(shí)際 sql 語(yǔ)句 
 */ 
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 語(yǔ)句中的占位符與參數(shù)個(gè)數(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); // 用來(lái)保存日志 
  
 return statement; 
} 
 
/** 
 * ? 和參數(shù)的實(shí)際個(gè)數(shù)是否匹配 
 * 
 * @param sql 
 *   SQL 語(yǔ)句,可以帶有 ? 的占位符 
 * @param params 
 *   插入到 SQL 中的參數(shù),可單個(gè)可多個(gè)可不填 
 * @return true 表示為 ? 和參數(shù)的實(shí)際個(gè)數(shù)匹配 
 */ 
private static boolean match(String sql, Object[] params) { 
 if(params == null || params.length == 0) return true; // 沒(méi)有參數(shù),完整輸出 
  
 Matcher m = Pattern.compile("(\\?)").matcher(sql); 
 int count = 0; 
 while (m.find()) { 
  count++; 
 } 
  
 return count == params.length; 
} 

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

我們不能保證那 SQL 可以直接放到數(shù)據(jù)庫(kù)中被解析。因?yàn)槲覀兊某踔灾皇前?SQL 打印出來(lái),務(wù)求更近一步讓程序員在開發(fā)階段看到 SQL 是怎么樣子的,而且不是一堆 ?、?……,這樣會(huì)顯得更符合真實(shí)情形一點(diǎn)。

PrepareStatement 內(nèi)部源碼肯定有這一步驟或者某個(gè)變量是表示那個(gè)真實(shí) SQL 的,——只是沒(méi)有暴露出來(lái)。如果有,那么對(duì)程序員會(huì)更友好一些。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Java實(shí)現(xiàn)的二叉樹常用操作【前序建樹,前中后遞歸非遞歸遍歷及層序遍歷】

    Java實(shí)現(xiàn)的二叉樹常用操作【前序建樹,前中后遞歸非遞歸遍歷及層序遍歷】

    這篇文章主要介紹了Java實(shí)現(xiàn)的二叉樹常用操作,包括二叉樹的前序建樹,前中后遞歸非遞歸遍歷及層序遍歷等相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01
  • 解決springboot configuration processor對(duì)maven子模塊不起作用的問(wèn)題

    解決springboot configuration processor對(duì)maven子模塊不起作用的問(wèn)題

    這篇文章主要介紹了解決springboot configuration processor對(duì)maven子模塊不起作用的問(wèn)題,本文通過(guò)圖文實(shí)例代碼給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • Spring Security實(shí)現(xiàn)身份認(rèn)證和授權(quán)的示例代碼

    Spring Security實(shí)現(xiàn)身份認(rèn)證和授權(quán)的示例代碼

    在 Spring Boot 應(yīng)用中使用 Spring Security 可以非常方便地實(shí)現(xiàn)用戶身份認(rèn)證和授權(quán),本文主要介紹了Spring Security實(shí)現(xiàn)身份認(rèn)證和授權(quán)的示例代碼,感興趣的可以了解一下
    2023-06-06
  • Java中的使用及連接Redis數(shù)據(jù)庫(kù)(附源碼)

    Java中的使用及連接Redis數(shù)據(jù)庫(kù)(附源碼)

    這篇文章主要介紹了Java中的使用及連接Redis數(shù)據(jù)庫(kù)(附源碼),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Spring框架生成圖片驗(yàn)證碼實(shí)例

    Spring框架生成圖片驗(yàn)證碼實(shí)例

    驗(yàn)證碼在很多地方都會(huì)遇到,實(shí)現(xiàn)的方法和形式也有很多,主要的目的就是為了安全,防止一些惡意的攻擊等。今天在之前搭建好的一個(gè)spring框架上寫了一個(gè)驗(yàn)證碼的生成demo,我會(huì)貼出細(xì)節(jié)代碼,但是spring的配置就不在介紹了,有需要的可以參考借鑒。
    2016-08-08
  • 手工搭建Servlet實(shí)現(xiàn)

    手工搭建Servlet實(shí)現(xiàn)

    現(xiàn)在作為一個(gè)Java程序員,我們已經(jīng)習(xí)慣了使用IDE和Web框架進(jìn)行開發(fā),IDE幫助我們做了編譯、打包的工作。Spring框架則幫助我們實(shí)現(xiàn)了Servlet接口,并把Servlet容器注冊(cè)到了Web容器中。本文主要介紹了Servlet手工搭建,感興趣的可以了解一下
    2021-07-07
  • java控制臺(tái)實(shí)現(xiàn)拼圖游戲

    java控制臺(tái)實(shí)現(xiàn)拼圖游戲

    這篇文章主要為大家詳細(xì)介紹了java控制臺(tái)實(shí)現(xiàn)拼圖游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Spring?Boot如何排除自動(dòng)加載數(shù)據(jù)源

    Spring?Boot如何排除自動(dòng)加載數(shù)據(jù)源

    這篇文章主要介紹了Spring?Boot如何排除自動(dòng)加載數(shù)據(jù)源,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 使用Maven中的scope總結(jié)

    使用Maven中的scope總結(jié)

    這篇文章主要介紹了使用Maven中的scope總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • spring boot如何使用spring AOP實(shí)現(xiàn)攔截器

    spring boot如何使用spring AOP實(shí)現(xiàn)攔截器

    本篇文章主要介紹了spring boot如何使用spring AOP實(shí)現(xiàn)攔截器,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04

最新評(píng)論

黄冈市| 仙居县| 滦南县| 湖北省| 泸州市| 正宁县| 密山市| 岳西县| 德钦县| 镇康县| 三台县| 衡阳市| 武宁县| 临朐县| 安新县| 永登县| 保靖县| 台州市| 家居| 徐闻县| 建水县| 安阳县| 汝城县| 玉环县| 加查县| 长泰县| 布尔津县| 五寨县| 夹江县| 岢岚县| 阳高县| 襄樊市| 灯塔市| 秭归县| 凯里市| 镇原县| 沧州市| 嘉祥县| 和静县| 霍林郭勒市| 嫩江县|