193 Stimmen

Abfrage aus java.sql.PreparedStatement holen

In meinem Code verwende ich java.sql.PreparedStatement .

Ich führe dann die setString() Methode, um die Platzhalter der vorbereiteten Anweisung aufzufüllen.

Gibt es eine Möglichkeit, die endgültige Abfrage abzurufen (und auszudrucken), bevor die executeQuery() Methode aufgerufen und die Abfrage ausgeführt wird? Ich möchte dies nur für Debugging-Zwecke.

194voto

BalusC Punkte 1034465

Dies ist nirgends im JDBC-API-Vertrag definiert, aber wenn Sie Glück kann der betreffende JDBC-Treiber das komplette SQL zurückgeben, indem er einfach PreparedStatement#toString() . D.h.

System.out.println(preparedStatement);

Meiner Erfahrung nach sind es zumindest die PostgreSQL 8.x und MySQL 5.x JDBC-Treiber, die dies tun.

Falls Ihr JDBC-Treiber dies nicht unterstützt, ist es am besten, einen Statement-Wrapper zu verwenden, der alle Aufrufe an setXxx() Methoden und füllt schließlich einen SQL-String auf toString() auf der Grundlage der aufgezeichneten Informationen. Eine bestehende Bibliothek, die dies tut, ist P6Spy . In der Zwischenzeit können Sie eine Verbesserungsanfrage an das Entwicklungsteam Ihres JDBC-Treibers stellen und hoffen, dass sie die gewünschte Funktion implementieren. toString() auch das Verhalten.

34voto

Rich Adams Punkte 25072

Sie könnten versuchen, Folgendes anzurufen toString() in der vorbereiteten Anweisung, nachdem Sie die Bindungswerte festgelegt haben.

PreparedStatement statement = connection.prepareStatement(aSQLStatement);
System.out.println("Before : " + statement.toString());
query.setString(1, "Hello");
query.setString(2, "World");
System.out.println("After : " + statement.toString());

Dies funktioniert, wenn Sie den JDBC-MySQL-Treiber verwenden, aber ich bin nicht sicher, ob dies auch in anderen Fällen der Fall ist. Möglicherweise müssen Sie alle Bindungen, die Sie vornehmen, nachverfolgen und diese dann ausdrucken.

Beispielhafte Ausgabe des obigen Codes.

Before : com.mysql.jdbc.JDBC4PreparedStatement@fa9cf: SELECT * FROM test WHERE blah1=** NOT SPECIFIED ** and blah2=** NOT SPECIFIED **
After : com.mysql.jdbc.JDBC4PreparedStatement@fa9cf: SELECT * FROM test WHERE blah1='Hello' and blah2='World'

53 Stimmen

Funktioniert leider nicht mit Oracle :(

10 Stimmen

Funktioniert nicht auch mit Sqlite!

4 Stimmen

Können Sie auf diese Weise Original-SQL vom Oracle-Treiber erhalten: ((OraclePreparedStatementWrapper) preparedStatement).getOriginalSql()

26voto

qwertzguy Punkte 12729

Für diejenigen unter Ihnen, die eine Lösung für Oracle suchen, habe ich eine Methode aus dem Code von Log4Jdbc erstellt. Sie müssen die Abfrage und die an das preparedStatement übergebenen Parameter bereitstellen, da das Abrufen dieser Parameter ein wenig mühsam ist:

private String generateActualSql(String sqlQuery, Object... parameters) {
    String[] parts = sqlQuery.split("\\?");
    StringBuilder sb = new StringBuilder();

    // This might be wrong if some '?' are used as litteral '?'
    for (int i = 0; i < parts.length; i++) {
        String part = parts[i];
        sb.append(part);
        if (i < parameters.length) {
            sb.append(formatParameter(parameters[i]));
        }
    }

    return sb.toString();
}

private String formatParameter(Object parameter) {
    if (parameter == null) {
        return "NULL";
    } else {
        if (parameter instanceof String) {
            return "'" + ((String) parameter).replace("'", "''") + "'";
        } else if (parameter instanceof Timestamp) {
            return "to_timestamp('" + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS").
                    format(parameter) + "', 'mm/dd/yyyy hh24:mi:ss.ff3')";
        } else if (parameter instanceof Date) {
            return "to_date('" + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").
                    format(parameter) + "', 'mm/dd/yyyy hh24:mi:ss')";
        } else if (parameter instanceof Boolean) {
            return ((Boolean) parameter).booleanValue() ? "1" : "0";
        } else {
            return parameter.toString();
        }
    }
}

3 Stimmen

OP möchte eine generierte Abfrage von PreparedStatement Objekt.

0 Stimmen

@ruslan 1. nein, das steht nicht im OP. 2. Es ist zum Beispiel bei Oracle nicht möglich.

10 Stimmen

Is there a way for me to retrieve (and print out) the final query before the executeQuery() method is called and the query is executed? . Er gibt eindeutig an, dass er die endgültige Abfrage nach Übergabe der Parameter an PreparedStatement .

12voto

sproketboy Punkte 8416

Sie können log4jdbc zu Ihrem Projekt hinzufügen. Dies fügt die Protokollierung von SQL-Befehlen während ihrer Ausführung sowie eine Menge anderer Informationen hinzu.

http://code.google.com/p/log4jdbc/wiki/FAQ

2 Stimmen

Hier ist ein großartiges Tutorial, wie man log4j benutzt cubrid.org/store_java_logs_to_databdase_using_log4j .

8voto

imxylz Punkte 7725

Wenn Sie nur die Abfrage protokollieren möchten, fügen Sie 'logger' und 'profileSQL' zur jdbc url hinzu:

&logger=com.mysql.jdbc.log.Slf4JLogger&profileSQL=true

Sie erhalten dann die folgende SQL-Anweisung:

2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 999 resultset: 0
2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 999 resultset: 0 message: SET sql_mode='NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES'
2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 999 resultset: 0
2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 2 connection: 19130945 statement: 13 resultset: 17 message: select 1
2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 0 connection: 19130945 statement: 13 resultset: 17
2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 15 resultset: 18 message: select @@session.tx_read_only
2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 0 connection: 19130945 statement: 15 resultset: 18
2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 2 connection: 19130945 statement: 14 resultset: 0 message: update sequence set seq=seq+incr where name='demo' and seq=4602
2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 0 connection: 19130945 statement: 14 resultset: 0

Der Standard-Logger ist:

com.mysql.jdbc.log.StandardLogger

Mysql jdbc-Eigenschaftsliste: https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X