3 回答

TA貢獻1798條經驗 獲得超7個贊
使用預準備語句,沒有“SQL查詢”:
您有一個包含占位符的聲明
它被發送到DB服務器
并在那里準備
這意味著SQL語句被“分析”,解析,表示它的一些數據結構在內存中準備
然后,你已經綁定了變量
它們被發送到服務器
并執行準備好的聲明 - 處理這些數據
但是沒有重構真正的實際SQL查詢 - 既不在Java端,也不在數據庫端。
因此,沒有辦法獲得準備好的語句的SQL - 因為沒有這樣的SQL。
出于調試目的,解決方案要么:
使用占位符和數據列表輸出語句的代碼
或者“手動”“構建”一些SQL查詢。

TA貢獻1876條經驗 獲得超7個贊
它在JDBC API合同中沒有任何定義,但是如果你很幸運,有問題的JDBC驅動程序可以通過調用返回完整的SQL PreparedStatement#toString()
。即
System.out.println(preparedStatement);
至少MySQL 5.x和PostgreSQL 8.x JDBC驅動程序支持它。但是,大多數其他JDBC驅動程序不支持它。如果你有這樣的,那么你最好的選擇是使用Log4jdbc或P6Spy。
或者,您也可以編寫一個泛型函數,它接受一個Connection
SQL字符串和語句值,并PreparedStatement
在記錄SQL字符串和值后返回一個。開球示例:
public static PreparedStatement prepareStatement(Connection connection, String sql, Object... values) throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < values.length; i++) { preparedStatement.setObject(i + 1, values[i]); } logger.debug(sql + " " + Arrays.asList(values)); return preparedStatement;}
并用它作為
try { connection = database.getConnection(); preparedStatement = prepareStatement(connection, SQL, values); resultSet = preparedStatement.executeQuery(); // ...
另一個替代方法是實現一個自定義PreparedStatement
,它包裝(修飾)構造中的實際 PreparedStatement
內容并覆蓋所有方法,以便它調用真實 的方法PreparedStatement
并收集所有setXXX()
方法中的值,并且懶惰地構造“實際”SQL字符串,只要其中一個executeXXX()
調用這些方法(非常有用,但是大多數IDE為裝飾器方法提供了自動生成器,Eclipse確實如此)。最后只需使用它。這也基本上是P6Spy和配件已經在引擎蓋下做的事情。

TA貢獻1836條經驗 獲得超13個贊
我正在使用帶有MySQL連接器v.5.1.31的Java 8,JDBC驅動程序。
我可以使用此方法獲得真正的SQL字符串:
// 1. make connection somehow, it's conn variable// 2. make prepered statement templatePreparedStatement stmt = conn.prepareStatement( "INSERT INTO oc_manufacturer" + " SET" + " manufacturer_id = ?," + " name = ?," + " sort_order=0;");// 3. fill templatestmt.setInt(1, 23);stmt.setString(2, 'Google');// 4. print sql stringSystem.out.println(((JDBC4PreparedStatement)stmt).asSql());
所以它返回像這樣的smth:
INSERT INTO oc_manufacturer SET manufacturer_id = 23, name = 'Google', sort_order=0;
添加回答
舉報