Почему я не могу отладить DatabaseMetaData? - PullRequest
2 голосов
/ 25 января 2011

У меня странная ситуация с небольшим приложением на Java, использующим JDBC-OBDC. Я проверяю базу данных с помощью класса DatabaseMetaData. Когда я запускаю программу, все работает без проблем. Но когда я хочу отладить, чтобы увидеть значения внутри Resulset, содержащего DatabaseMetaData, java.sql.SQLException выбрасывается, только если я ставлю точку останова в то время Вот мой код:

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

Почему я не могу поместить свою точку останова в этот раздел кода ??

Это 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)

Строка Snooper.java:56 в моем коде относится к

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

Спасибо.

Ответы [ 2 ]

3 голосов
/ 26 января 2011

Я установил SQL Server, чтобы воспроизвести вашу проблему и проверить ее.

Краткое объяснение

Вы должны прочитать значения ТОЛЬКО ОДИН РАЗ и в ЗАКАЗАТЬ они появляются в ВЫБОР. JdbcOdbc отстой. Во время отладки вы читаете их несколько раз.

Длинное объяснение

Что вы делаете, это проверка состояния объекта в отладчике , что приводит к динамическим результатам.

В данном случае это sun.jdbc.odbc.JdbcOdbcResultSet и выполняется выражение resultSet.getString(...) несколько раз. В первый раз это будет работать (в случае, если ваша точка останова приостанавливает поток до того, как будет задан resultSet). Затем, во второй раз, когда вы (или ваш отладчик) снова проверяете значение выражения, метод getString() снова вызывается , и этот метод изменяет внутреннее состояние объекта ResultSet .

Хотя название метода предполагает, что это простой метод получения, это не так. Это делает больше, чем это. Он может фактически получать данные из базы данных, изменять свои внутренние счетчики положения и т. Д. Вы не можете выполнять методы получения несколько раз.

Драйвер ODBC - очень плохая вещь и низкого качества. Ожидайте странного поведения и других драконов. Вы можете получить отладочную информацию, включив трассировку JdbcOdbc. Это можно сделать, установив LogWriter в DriverManager до активации JdbcOdbc-Bridge:

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

Затем вы получите подробный вывод отладочной информации JdbcOdbc-Driver, как показано ниже. Это может помочь вам отладить проблему, которая у вас есть. При отладке просто сохраняйте данные, полученные из объектов ResultSet, в локальных объектах, чтобы их можно было многократно проверять в отладчике.

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. И это было воспроизведенное исключение, включая номера строк кода Sun для JDK 1.6.0_22. Как видно из первой строки, это то, что выводится на консоль, когда я проверял метод 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)
1 голос
/ 25 января 2011

Да, отладчик работает в потоке, отличном от метаданных, полученных con.getMetaData(); ... так что, вы знаете, это другая транзакция с другими метаданными.

Ну, хорошо, это было бымое первое предположение.Я не проверял исходный код драйвера Obdc для подтверждения.


Редактировать: спасибо за отличное замечание mhaller a сделал второй взгляд / предположение: вы вызываете wasNull () преждевременно, это имеет значение после некоторой операции getResultSet.Скопируйте из 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>.

тьфу, я сосу сегодня вечером!

...