Domanda

Ho una situazione strana con una piccola applicazione in Java utilizzando un JDBC-OBDC. Sto ispezionando un database utilizzando la classe DatabaseMetaData. Quando eseguire il programma, tutto funziona senza anyproblem. Ma quando voglio debug per vedere i valori all'interno della Resulset che contiene il DatabaseMetaData un java.sql.SQLException è gettato solo se ho messo un punto di interruzione all'interno del tempo. Ecco il mio codice:

DatabaseMetaData patrol = con.getMetaData();
ResultSet answer = patrol.getTables(null, null, null, null);
        while(answer.next()) {
            if (answer.wasNull() == false) {
                tableNamesAsOne = tableNamesAsOne + answer.getString("TABLE_NAME") + " ";
            }
        }
        answer.close();

Perché non riesco a mettere il mio punto di interruzione in questa sezione di codice ??

Questa è la printStackTrace.

Exception in thread "main" java.sql.SQLException: No data found
    at sun.jdbc.odbc.JdbcOdbc.standardError(Unknown Source)
    at sun.jdbc.odbc.JdbcOdbc.SQLGetDataString(Unknown Source)
    at sun.jdbc.odbc.JdbcOdbcResultSet.getDataString(Unknown Source)
    at sun.jdbc.odbc.JdbcOdbcResultSet.getString(Unknown Source)
    at sun.jdbc.odbc.JdbcOdbcResultSet.getString(Unknown Source)
    at Snooper.inspect(Snooper.java:56)
    at Snooper.<init>(Snooper.java:26)
    at Snooper.createAndShowGUI(Snooper.java:112)
    at Snooper.main(Snooper.java:125)

Linea Snooper.java:56 nel mio codice si riferisce a

tableNamesAsOne = tableNamesAsOne + answer.getString("TABLE_NAME") + " ";

Grazie.

È stato utile?

Soluzione

Ho installato SQL Server per riprodurre il problema e verificare esso.

Breve spiegazione

È necessario leggere i valori di SOLO UNA VOLTA e Ordine in cui appaiono nella SELECT. JdbcOdbc fa schifo. Durante il debug, stai leggendo loro più volte.

lunga spiegazione

Quello che state facendo è ispezionare un oggetto stateful nel debugger , che porta a risultati dinamici.

In questo caso è il sun.jdbc.odbc.JdbcOdbcResultSet ed eseguendo il resultSet.getString(...) espressione più volte. La prima volta, funzionerà (nel caso in cui il punto di interruzione sospende il filo prima il gruppo di risultati viene chiesto). Poi, la seconda volta (o il vostro debugger) ispeziona il valore dell'espressione di nuovo, il metodo getString() viene chiamato nuovo e questo metodo cambia lo stato interno dell'oggetto ResultSet .

Anche se suggerisce il nome del metodo è un semplice getter, non lo è. Lo fa di più. Si può effettivamente recuperare i dati dal database, modificare i suoi contatori di posizione interne ecc Non è possibile eseguire i metodi getter più volte.

Il driver ODBC è una cosa molto brutta e di scarsa qualità. Aspettatevi strano comportamento e altri draghi. È possibile ottenere alcune informazioni di debug, consentendo JdbcOdbc Tracing. Questo viene fatto impostando un LogWriter sul DriverManager, prima che il JdbcOdbc-Bridge è attivato:

java.sql.DriverManager.setLogWriter(new PrintWriter(System.out));

Quindi, si otterrà verbose debug del JdbcOdbc-driver come il seguente. Può essere utile eseguire il debug del problema che avete. Quando il debug, solo garantire per memorizzare i dati recuperati dal ResultSet oggetti in oggetti locali, in modo da poter ispezionare loro più volte nel debugger.

DriverManager.getConnection("jdbc:odbc:testdbodbc")
JdbcOdbcDriver class loaded
registerDriver: driver[className=sun.jdbc.odbc.JdbcOdbcDriver,sun.jdbc.odbc.JdbcOdbcDriver@7b479feb]
DriverManager.initialize: jdbc.drivers = null
JDBC DriverManager initialized
    trying driver[className=sun.jdbc.odbc.JdbcOdbcDriver,sun.jdbc.odbc.JdbcOdbcDriver@7b479feb]
*Driver.connect (jdbc:odbc:testdbodbc)
JDBC to ODBC Bridge: Checking security
No SecurityManager present, assuming trusted application/applet
JDBC to ODBC Bridge 2.0001
Current Date/Time: Wed Jan 26 00:31:27 CET 2011
Loading JdbcOdbc library
Allocating Environment handle (SQLAllocEnv)
hEnv=115724512
Allocating Connection handle (SQLAllocConnect)
hDbc=116219184
Connecting (SQLDriverConnect), hDbc=116219184, szConnStrIn=DSN=testdbodbc
RETCODE = 1
WARNING - Generating SQLWarning...
SQLWarning: reason([Microsoft][ODBC SQL Server Driver][SQL Server]Changed database context to 'master'.) SQLState(01000) vendor code(5701)
SQLWarning: reason([Microsoft][ODBC SQL Server Driver][SQL Server]Changed language setting to us_english.) SQLState(01000) vendor code(5703)
*Connection.getMetaData
*DatabaseMetaData.getDriverName
Get connection info string (SQLGetInfo), hDbc=116219184, fInfoType=6, len=300
SQLSRV32.DLL
*DatabaseMetaData.getDriverVersion
Get connection info string (SQLGetInfo), hDbc=116219184, fInfoType=7, len=300
06.01.7600
*DatabaseMetaData.getDriverName
Get connection info string (SQLGetInfo), hDbc=116219184, fInfoType=6, len=300
SQLSRV32.DLL
Driver name:    JDBC-ODBC Bridge (SQLSRV32.DLL)
*DatabaseMetaData.getDriverVersion

P.S. E questo era l'eccezione riprodotto, compresi i numeri di riga del codice Sun per JDK 1.6.0_22. Come si può vedere nella prima riga, questo è ciò che è stampato sulla console, quando ho controllato il metodo getString().

Get string data (SQLGetData), hStmt=108067024, column=3, maxLen=257
RETCODE = 100
ERROR - No data found
java.sql.SQLException: No data found
at sun.jdbc.odbc.JdbcOdbc.standardError(JdbcOdbc.java:7138)
at sun.jdbc.odbc.JdbcOdbc.SQLGetDataString(JdbcOdbc.java:3907)
at sun.jdbc.odbc.JdbcOdbcResultSet.getDataString(JdbcOdbcResultSet.java:5698)
at sun.jdbc.odbc.JdbcOdbcResultSet.getString(JdbcOdbcResultSet.java:354)
at sun.jdbc.odbc.JdbcOdbcResultSet.getString(JdbcOdbcResultSet.java:411)
at sandbox.DatabaseMetadataTest.testDBMetadata(DatabaseMetadataTest.java:27)

Altri suggerimenti

Si, le piste debugger in un thread diverso da quello del metadati ottenuto dalla con.getMetaData(); ... così, si sa, è un'operazione diversa con un metadati diversi.

Beh, ok, che sarebbe la mia prima ipotesi. Non ho guardato in OBDC codice sorgente del driver per confermare.


Modifica: grazie per mhaller eccellente osservazione di un fatto un secondo sguardo / indovinare: si chiama wasNull () prematuramente, che ha un senso dopo qualche operazione get del ResultSet. Copia da javadoc

 * Note that you must first call one of the getter methods
 * on a column to try to read its value and then call
 * the method <code>wasNull</code> to see if the value read was
 * SQL <code>NULL</code>.

uff, mi fa schifo stasera!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top