2017-02-19 10 views
1

データベースからオブジェクトを取得するのに役立つ関数がいくつかあります。resultSet.next()は、テーブルにデータが格納されていてもfalseを返します。

public User getUser(int beamID) throws NoSuchUserException { 
    return userFromResultSet(getUserResultSet(beamID)); 
} 


private ResultSet getUserResultSet(int beamID) { 
    try(Connection conn = dataSource.getConnection()) { 

     // queries.getUserByBeamID() returns "SELECT * FROM user WHERE beamID=?" 
     PreparedStatement stmt = conn.prepareStatement(queries.getUserByBeamID()); 

     stmt.setInt(1, beamID); 
     System.out.println(stmt.toString()); 
     return stmt.executeQuery(); 

    } catch (SQLException e) { 
     e.printStackTrace(); 
     throw new IllegalStateException(); 
    } 
} 

private User userFromResultSet(ResultSet resultSet) { 
    try { 
     boolean next = resultSet.next(); // Debugger tells me this is false. 
     if (!next) 
      throw new NoSuchUserException(); 

     User user = new User(this, 
      resultSet.getInt("beamID"), 
      resultSet.getString("name"), 
      resultSet.getInt("points"), 
      resultSet.getInt("time") 
     ); 

     if (resultSet.next()) 
      throw new IllegalStateException("Duplicate user entries exist - database integrity compromised!"); 

     return user; 
    } catch (SQLException e) { 
     e.printStackTrace(); 
     throw new IllegalStateException(); 
    } 
} 

奇妙なことは、私は、データを知っている、あるは二つの理由が存在しない:

  • 私のプログラムは、それが存在しない場合、エントリを作成しようとしが、それが与えるしようユニーク制約に従わないエラー。私のSQLiteのDBブラウザでクエリを実行する

  • だけで正常に動作します:

The query returns a result, as it should.

これは、ファイルベースのデータベースであるように私は非常に、これはコミットされていないデータの問題であることを疑いますそのファイルをテキストエディタで開くと、データ内のユーザー名のインスタンスが表示されます。あなたはここで何をしているかの密接

+1

"エントリが存在しない場合は、プログラムがそのエントリを作成しようとしますが、ユニークな制約が適用されていないというエラーが表示されます。**" - つまり、 **存在しない(そうでなければ、それを作成しようとせず、一意的な制約違反となる)が、ユニーク制約は 'beam_id'の代わりにまたは 'beam_id'に加えて' id'にある可能性が高い –

答えて

6

ルック:

try (Connection conn = dataSource.getConnection()) { 
    PreparedStatement stmt = conn.prepareStatement(queries.getUserByBeamID()); 

    stmt.setInt(1, beamID); 
    System.out.println(stmt.toString()); 
    return stmt.executeQuery(); 
} catch (SQLException e) { 
    e.printStackTrace(); 
    throw new IllegalStateException(); 
} 

私はそれを試す - と - リソース表現の実行が終了した後、try句で指定されたリソースを閉じる保証するための契約であると考えています。結果セットもtryブロックの最後に閉じられていると考えています。したがって、何もないので、next()を呼び出すとfalseが返されます。

私はあなたのコードを書かれているような方法がtryブロック内User POJOを移入し、結果セットを返す代わりにUserオブジェクトを返すことです:

private User getUserResultSet(int beamID) { 
    User user = null; 
    try (Connection conn = dataSource.getConnection()) { 
     PreparedStatement stmt = conn.prepareStatement(queries.getUserByBeamID()); 

     stmt.setInt(1, beamID); 

     ResultSet rs = stmt.executeQuery(); 
     user = new User(this, 
      rs.getInt("beamID"), 
      rs.getString("name"), 
      rs.getInt("points"), 
      rs.getInt("time") 
     ); 

    } catch (SQLException e) { 
     e.printStackTrace(); 
     throw new IllegalStateException(); 
    } 

    return user; 
} 

今の懸念のあなたの分離がより優れています前。接続や結果セットなどで何か問題が発生した場合は、それらを処理する実際のコードで処理されます。例外またはその他のエラーが発生した場合は、nullユーザオブジェクトが返されます。この可能性を処理するためにコードを更新する必要があります。

+0

「ResultSet.next()」のjavadocは、データベースアクセスエラーが発生した場合、またはこのメソッドが閉じられた結果セットで呼び出された場合に「SQLExceptionをスローする」ことを示しています。それが理由ならば、OPはSQLExceptionを受け取っていて、 'false'ではないはずです。しかし、ドライバが壊れている可能性があり、JDBC仕様を正しく実装していない可能性があります。 –

+0

@ErwinBolwidtこれも私の心を越えましたが、私が読んだのはドライバー固有のものでした。あなたが有効なクエリで_result set_が空であることについてのより良い説明があれば、答えを投稿してください。 –

+1

これは、実際には、これを解決しました。 try-with-resourcesの中でResultSetの使い方を入れ子にしました。うまくいきました。ご協力いただきありがとうございます! –

関連する問題