web-dev-qa-db-ja.com

空の結果セットを返すJDBC

非常にシンプルなデータベース接続にJDBCを使用しています。

接続/ステートメントを作成し、クエリを実行しました。デバッガーでステートメントのクエリオブジェクトをチェックして、適切なクエリが送信されていることを確認します。次に、データベースでクエリを(デバッガから直接コピーして)ダブルチェックし、データが返されることを確認しました。ただし、返された結果セットは.next()でfalseを返します

私が見逃している一般的な落とし穴はありますか?

public List<InterestGroup> getGroups() {
    myDB.sendQuery("select distinct group_name From group_members where
            username='" + this.username + "'");
    ResultSet results = myDB.getResults();
    List<InterestGroup> returnList = new ArrayList<InterestGroup>();
    try {
        while (results.next()) {
            returnList.add(new InterestGroup(results.getString("group_name"), myDB));
        } 
        return returnList;
    } catch (SQLException e) {
        e.printStackTrace();
        return null;
    }

}

そして、myDBクラス(接続/ステートメントコードを任意のプロジェクトにドロップできる単純なラッパー)

public void sendQuery(String query){
    this.query = query;
    try {
        if(statement == null){
            statement = connection.createStatement();
        }
        results = statement.executeQuery(query);
    } catch (SQLException e) {
        System.out.println(query);
        currentError = e;
        results = null;
        printError(e, "querying");
    }

}

public ResultSet getResults(){
    return results;
}

編集:提案に基づいて、私はほとんど私のコードを改良しましたが、それでも同じ問題があります。以下は、同じ問題があるコードの簡略化された部分です。

private boolean attemptLogin(String uName, String pWord) {

    ResultSet results;
    try{
        try {
            Class.forName("Oracle.jdbc.driver.OracleDriver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        connection =DriverManager.getConnection(connectionString,user,password);
        PreparedStatement statement = connection.prepareStatement("select username from users where username='testuser'");
        results = statement.executeQuery();
        if(results != null && results.next()){
            System.out.println("found a result");
            statement.close();
            return true;
        }
        System.out.println("did not find a result");
        statement.close();
        return false;
    }catch(SQLException e){
        e.printStackTrace();
        return false;
    }

}

また、このエラーの原因を排除するために、今のところクエリをハードコードしました。以前と同じ問題(これはすべてのクエリで発生します)。デバッガーはインスタンス化されるすべてのオブジェクトを表示し、スタックトレースは出力されません。さらに、別のプロジェクトで同じコード(および前述のより複雑なコード)を使用できます。

17
dpsthree

私はそれを考え出した....愚かなOracleは私が持っている同時接続の数が好きではなかった(2つすべて、1つはコンソール用、もう1つはJava用)。残念ながら、サーバーは私の制御下にないので、私はそれに対処する必要があります。オラクルはより良い対応を提供すると思います。代わりに、空の結果セットを返しました。

回答ありがとうございます

編集これが尋ねられた/答えられたので、根本的な原因は使用中のコミット/トランザクション設定に関連している可能性が高いと多くの人々が指摘しています。追加のヒントと考えられる解決策については、他の回答を必ず確認してください。

22
dpsthree

コードにいくつかの落とし穴があります。問題が発生する可能性のある箇所がいくつかあります。

まず、通常のステートメントの使用。 準備済みステートメント を使用して、 SQLインジェクション で問題が発生しないようにします。

の代わりに

_statement = connection.createStatement();
_

使用する

_statement = connection.prepareStatement(String sql);
_

これにより、クエリは次のようになります

_"select distinct group_name From group_members where username= ?"
_

そしてあなたはユーザー名を

_ statement.setString(1, username);
_

次に、myDBクラスを使用したくありません。結果がnullの場合はどうなりますか? public List<InterestGroup> getGroups()メソッドでエラーチェックを行っていません。

public void sendQuery(String query)voidであってはならないようですが、ResultSetを返す必要があります。また、JDBC例外処理を行う適切な方法については、ネットで検索してください。

また、この行:

_new InterestGroup(results.getString("group_name"), myDB)
_

パラメータとしてmyDBを使用するのはなぜですか?

コードに_System.out.println_ステートメントを追加して、問題が発生する可能性のある場所を確認することをお勧めします。

9
darioo

Java.sql.connectionでは、接続を作成した後でこのメソッドを呼び出す必要があります。

conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

oracleにも同様の方法があるかもしれません。

5
user805125

同じことが私にも起こりました。私はSQL Developerを使用してデータベースにテストデータを挿入し、JDBCを使用してテスト読み取りしました。しかし、私が得たのは空の結果セットだけでした。列名とすべてを取得できましたが、データの読み取りに問題がありました。前にdpsthreeで指摘したように、SQL Developer IDEから切断しましたが、終了時にコミットするように求められました。

出来上がり!問題は、挿入コマンドを使用したデータベースへの変更がコミットされなかったことでした。

SQL Developerの場合、これはPreferences> Database> Advanced> Autocommitにあります

これは私の問題を解決しました。

4
anuvab1911

最も一般的なのは、クエリに複数のステートメントを含めることです。

desc table;
select * from sometable where etc.;

結果を返さないステートメントの場合、別の構成を使用する必要があります。これでもクライアントは窒息します:

select * from sometable where whatever;
select * from sometable where something else;

同じ形状の2つの結果セットは、クライアントをビフにします。

3
wallyk

過去には、次のようなコードで同様の問題がありました。

querystr = "your sql select query string"

resultset = statement.executeQuery(querystr)

while (resultset.next())
{
//do something with the data. 
//if you do something fairly involved in this block (sequentially, in the same thread)
//such as calling a function that acts on the data returned from the resultset etc.
//it causes the resultset fetch to wait long enough for resultset.next() to 
//unexpectedly return null in the middle of everything
}

この状況で私が行ったのは、resultet.next()での最小の待機時間ですべてのデータをローカルメモリデータ構造にロードすることでした。次に、結果セットを正常に閉じた後、ローカルデータ構造からのデータに対して必要なことをすべて行いました。この動作は、Windows XP上のUnixバックエンド/ JDK 1.6.0_22クライアント上のOracle 10で発生していました。

お役に立てれば。

2
Chirantan

次に、データベースでクエリを(デバッガから直接コピーして)ダブルチェックし、データが返されることを確認しました。

この問題のあるエンジニアに、この検証を目の前で実演してもらいました。プログラムの1つのデータベースアカウントと、対話型SQLシェルの別のデータベースアカウントでログインしたことがわかります。 [これはOracle 8でした。]

2
Bert F

ええ、私はOPと同じ問題がありました。同じユーザーのデータベースに2つ以上のオープンな接続がある場合に発生します。たとえば、SQL Developerの1つの接続とJavaの1つの接続。結果は常に空の結果セットです。

編集:また、プロシージャを実行したり、データベースに挿入したりして、トランザクションをコミットしないときにも発生します。

1
westman379

テーブルがcommittedでないことが条件である可能性があります。新しいレコードを挿入してから、SQL実行コマンドウィンドウでコミットし、コードを実行します。

1
Shara Rizvi

Plsqlクライアントを使用してサーバーにログインし、コードから接続しようとしました。

接続は成功しましたが、結果セットにレコードがありませんでした。

サーバーからログアウトした後にのみ、結果セットが入力されました。

@dpsthreeに同意します。Oracleは適切なエラー/警告メッセージを提供する必要があります。

1
Yash

結果セットを反復するまで接続とステートメントObjectが生きているかどうかを確認してください。知らないうちに終了する場合があります。

1
gmhk

私の場合、SQL開発者で機能したクエリはJavaでは機能しませんでした。

*select * from table where process_date like '2014-08-06%'* (worked in sql developer)

javaで機能させるために、process_dateをcharにフォーマットするのに役立ちました

*select * from table where to_char(process_date) = '06-AUG-14'*
0
user3916827

私にとっての問題は、主キー列の作成時にNOT NULL ENABLEがあったことでした。のように...

CREATE TABLE SYSTEM_SETTINGS  ( 
  SYSTEM_SETTING_ID NUMBER(9,0) NOT NULL ENABLE, 
    "KEY" VARCHAR2(50 BYTE), 
    "VALUE" VARCHAR2(128 BYTE),
     CONSTRAINT "PK_SYSTEM_SETTINGS" PRIMARY KEY (SYSTEM_SETTING_ID)) 
TABLESPACE USERS;

そのようにせずにテーブルを再作成したとき

CREATE TABLE SYSTEM_SETTINGS  ( 
  SYSTEM_SETTING_ID NUMBER(9,0), 
    "KEY" VARCHAR2(50 BYTE), 
    "VALUE" VARCHAR2(128 BYTE),
     CONSTRAINT "PK_SYSTEM_SETTINGS" PRIMARY KEY (SYSTEM_SETTING_ID)) 
TABLESPACE USERS;

JDBC経由で動作し始めました。私は、jdbcドライバーにojdbc6.jarを使用しています。

0
Martin Benns

クエリの行の値を取得する必要がある場合でも、resultSetはfalseを返します。クエリのSQL端末でcommit;と記述していない可能性があるため、rs.next()がfalseを返します。これを実行した後、rs.next()をTrueとして取得します。

0
Sushmita Mitkar