您好,登錄后才能下訂單哦!
今天小編給大家分享一下JDBC查詢?nèi)罩居涗浀姆椒ㄓ心男┑南嚓P(guān)知識點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
在大多數(shù)情況下,JDBCPreparedStatement
使執(zhí)行數(shù)據(jù)庫查詢變得更加容易,并且可以顯著提高你的整體應(yīng)用程序性能。但是PreparedStatement
當(dāng)涉及到記錄查詢語句時(shí),該接口就不夠用了。盡管 aPreparedStatement
的優(yōu)勢在于其可變性,但一個好的日志條目必須準(zhǔn)確描述發(fā)送到數(shù)據(jù)庫的 SQL 在所有參數(shù)占位符已被實(shí)際參數(shù)值替換后的外觀。盡管有多種方法可以解決這個難題,但沒有一種方法可以輕松大規(guī)模實(shí)現(xiàn),而且大多數(shù)方法都會使你的代碼變得混亂。
在本文中,你將學(xué)習(xí)如何擴(kuò)展 JDBCPreparedStatement
接口以進(jìn)行查詢?nèi)罩居涗?。雖然LoggableStatement
類實(shí)現(xiàn)的PreparedStatement
接口,但增加了在適合于記錄的格式獲得查詢字符串的方法。使用LoggableStatement
該類既可以減少日志代碼中的錯誤發(fā)生率,又可以隨著時(shí)間的推移生成更整潔、更易于管理的代碼。
請注意,本文假設(shè)你之前有使用 JDBC 和PreparedStatement
類的經(jīng)驗(yàn)。
清單 1 說明了PreparedStatement
在進(jìn)行數(shù)據(jù)庫查詢時(shí)通常如何使用 a
(盡管省略了初始化和錯誤處理)。我們將使用SQL查詢SELECT我們的例子在這篇文章中,但討論也同樣適用于其他類型的SQL語句如DELETE,UPDATE和INSERT。
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 中的問號已替換為每個參數(shù)的值。
System.out.println("Executing query: select foo, bar from foobar where foo
< "+fooValue+" and bar = '+barValue+"'")
更好的方法是創(chuàng)建一個方法,我們稱之為replaceFirstQuestionMark
,它接受查詢字符串并用參數(shù)值替換問號,如清單 2 所示。使用這種方法消除了創(chuàng)建重復(fù)字符串來描述的需要SQL 語句。
// listing 1 goes here
sql = replaceFirstQuestionMark(sql, fooValue);
sql = replaceFirstQuestionMark(sql, barValue);
System.out.println("Executing query: "+sql);
雖然易于實(shí)施,但這些解決方案都不是理想的。問題是,每當(dāng)對 SQL 模板進(jìn)行更改時(shí),日志記錄代碼也必須更改。在某些時(shí)候你會犯錯誤幾乎是不可避免的。查詢將被更改,但您將忘記更新日志記錄代碼,并且你最終會得到與發(fā)送到數(shù)據(jù)庫的查詢不匹配的日志條目——這是調(diào)試噩夢。
我們真正需要的是一個設(shè)計(jì),讓我們使用的每個參數(shù)變量(fooValue
和barValue
在我們的例子)只有一次。我們想要一種方法,它可以讓我們獲取參數(shù)占位符替換為實(shí)際值的查詢字符串。因?yàn)?code>java.sql.PreparedStatement沒有這樣的方法,我們必須自己實(shí)現(xiàn)一個。
我們的自定義實(shí)現(xiàn)PreparedStatement
將充當(dāng) JDBC 驅(qū)動程序提供的“真實(shí)語句”的包裝器。包裝器語句會將所有方法調(diào)用(例如,setLong(int, long)
和setString(int,String))
轉(zhuǎn)發(fā)到“真實(shí)語句”。在這樣做之前,它將保存相關(guān)的參數(shù)值,以便它們可用于生成日志輸出。
清單 3 顯示了LoggableStatement
類是如何實(shí)現(xiàn)的java.sql.PreparedStatement
,以及它是如何使用 JDBC 連接和 SQL 模板作為輸入來構(gòu)建的。
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()
方法的調(diào)用,以及如何在方法setLong
和 setString
的 real語句
上調(diào)用相應(yīng)的方法。saveQueryParamValue()
調(diào)用以類似的方式添加到用于參數(shù)設(shè)置的所有方法(例如setChar
,setLong
、setRef
、 和setObj
)。清單 4 還展示了在不調(diào)用saveQueryParamValue()
的情況下如何包裝方法executeQuery
,因?yàn)樗皇恰皡?shù)設(shè)置”方法。
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 所示。它將每個參數(shù)值轉(zhuǎn)換為一種String
表示形式,并將其保存以供該getQueryString
方法以后使用。默認(rèn)情況下,對象將String
使用其toString
方法轉(zhuǎn)換為 a
,但如果對象是 aString
或 a Date
,它將用單引號 (")
括起來。getQueryString()
方法允許你從日志中復(fù)制大多數(shù)查詢并將它們粘貼到交互式 SQL 處理器中進(jìn)行測試和調(diào)試,而無需修改。你可以根據(jù)需要修改該方法以轉(zhuǎn)換其他類的參數(shù)值。
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);
}
當(dāng)使用標(biāo)準(zhǔn)方法設(shè)置所有參數(shù)時(shí),我們只需調(diào)用我們的getQueryString()
方法LoggableStatement
來獲取查詢字符串。所有問號都將替換為實(shí)際參數(shù)值,這些值已準(zhǔn)備好輸出到我們選擇的日志記錄目的地。
清單 6 顯示了如何將清單 1 和 2 中的代碼更改為使用LoggableStatement
。在我們的應(yīng)用程序代碼引入LoggableStatement
解決了重復(fù)參數(shù)變量的問題。當(dāng)對SQL模板進(jìn)行更改時(shí),我們只需要更新PreparedStatement
參數(shù)設(shè)置調(diào)用(例如,添加pstmt.setString(3,"new-param-value")
)。更改將反映在日志輸出中,無需對日志代碼進(jìn)行任何手動更新。
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查詢?nèi)罩居涗浀姆椒ㄓ心男边@篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。