Question

J'ai une situation étrange avec une petite application en Java en utilisant un JDBC-ODBC. J'inspectant une base de données en utilisant la classe DatabaseMetaData. Lorsque j'exécute le programme, tout fonctionne sans anyproblem. Mais quand je veux debug pour voir les valeurs à l'intérieur du Resulset contenant le DatabaseMetaData un java.sql.SQLException est jeté que si je mets un point d'arrêt dans le temps. Voici mon code:

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();

Pourquoi je ne peux pas mettre mon point d'arrêt dans cette section de code ??

est le 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)

Ligne Snooper.java:56 dans mon code fait référence à

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

Merci.

Était-ce utile?

La solution

J'ai installé SQL Server pour reproduire votre problème et vérifier.

Brève explication

Vous devez lire les valeurs UNE SEULE FOIS et ORDER ils apparaissent dans le SELECT. JdbcOdbc suce. Lors du débogage, vous les lire plusieurs fois.

longue explication

Ce que vous faites est inspectant un objet stateful dans le débogueur , ce qui conduit à des résultats de dynamiques.

Dans ce cas, il est le sun.jdbc.odbc.JdbcOdbcResultSet et l'exécution de l'expression resultSet.getString(...) plusieurs fois. La première fois, cela fonctionnera (dans le cas où votre point d'arrêt suspend le fil avant la resultSet est demandé). Ensuite, la deuxième fois que vous (ou votre débogueur) inspecte à nouveau la valeur de l'expression, la méthode getString() est appelée nouveau et cette méthode modifie l'état interne de l'objet ResultSet .

Bien que le nom l'indique est un getter simple, de la méthode, ce n'est pas. Il fait plus que cela. Il peut effectivement récupérer les données de la base de données, changer ses compteurs de position internes, etc. Vous ne pouvez pas exécuter les méthodes de lecture à plusieurs reprises.

Le pilote ODBC est une très mauvaise chose et de mauvaise qualité. Attendez-vous à un comportement étrange et d'autres dragons. Vous pouvez obtenir des informations de débogage en permettant JdbcOdbc Tracing. Cela se fait en définissant une LogWriter sur le DriverManager, avant la JdbcOdbc-Bridge est activé:

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

Ensuite, vous obtiendrez verbeux débogage sortie du JdbcOdbc-pilote comme suit. Il peut vous aider à déboguer le problème que vous avez. Lors du débogage, assurez-vous juste pour stocker les données récupérées à partir des objets ResultSet dans les objets locaux, afin que vous puissiez les consulter à plusieurs reprises dans le débogueur.

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. Et ce fut l'exception reproduite, y compris les numéros de ligne du code Sun pour JDK 1.6.0_22. Comme vous pouvez le voir dans la première ligne, voici ce qui est imprimé sur la console quand je visitai la méthode 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)

Autres conseils

Ouais, les pistes de débogage dans un autre thread que les métadonnées obtenues par con.getMetaData(); ... donc, vous le savez, il est une autre transaction avec des métadonnées différentes.

Bon, ok, ce serait ma 1ère estimation. Je ne l'ai pas regardé dans le code source du pilote OBDC pour confirmer.


Edit: merci pour mhaller excellente remarque a fait un 2ème regard / deviner: vous appelez wasNull () prématurément, il a un sens après une opération d'obtention du ResultSet. Copie de 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>.

ouf, me suce ce soir!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top