2

JDBC-OBDC を使用した Java の小さなアプリケーションで奇妙な状況が発生しました。DatabaseMetaData クラスを使用してデータベースを検査しています。プログラムを実行すると、すべて問題なく動作します。しかし、DatabaseMetaData を含む Resulset 内の値を確認するためにデバッグしたい場合、while 内にブレークポイントを配置した場合にのみ 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") + " ";

ありがとう。

4

2 に答える 2

3

問題を再現して検証するために SQL Server をインストールしました。

簡単な説明

値は一度だけ読み取る必要があり、それらはSELECTに表示されるORDER内にあります。JdbcOdbc は最悪です。デバッグ中は、それらを複数回読んでいます。

長い説明

あなたがしていることは、動的な結果につながるデバッガーでステートフル オブジェクトを検査することです。

この場合sun.jdbc.odbc.JdbcOdbcResultSet、式をresultSet.getString(...)複数回実行します。初めて機能します(結果セットが要求される前にブレークポイントがスレッドを一時停止する場合)。次に、ユーザー (またはデバッガー) が再度式の値を調べると、メソッドが再度getString()呼び出され、このメソッドがobjectの内部状態を変更します。ResultSet

メソッドの名前は単純な getter であることを示唆していますが、そうではありません。それ以上のことをします。実際にデータベースからデータを取得したり、内部の位置カウンターを変更したりする場合があります。getter メソッドを複数回実行することはできません。

ODBC ドライバーは非常に悪いものであり、低品質です。奇妙な行動や他のドラゴンを期待してください。JdbcOdbc Tracing を有効にすると、デバッグ情報を取得できます。LogWriterこれは、JdbcOdbc-Bridge がアクティブ化される前に、DriverManager でa を設定することによって行われます。

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

PS そして、これは JDK 1.6.0_22 の Sun コードの行番号を含む再現された例外でした。最初の行でわかるように、これは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)
于 2011-01-25T23:37:43.933 に答える
1

ええ、デバッガーは、によって取得されたメタデータとは別のスレッドで実行されcon.getMetaData();ます...つまり、別のメタデータを持つ別のトランザクションです。

そうですね、それが私の最初の推測です。確認のために Obdc ドライバーのソース コードを調べていません。


編集: mhaller の優れた発言に感謝し、2 番目の外観/推測を作成しました: wasNull() を時期尚早に呼び出します。ResultSet の取得操作の後に意味があります。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>.

ふぅ、今夜は最悪だ!

于 2011-01-25T18:52:17.227 に答える