2017-02-19 9 views
1

Ich habe ein paar Funktionen, die beim Abrufen der Objekte aus der Datenbank helfen.resultSet.next() gibt false zurück, obwohl die Tabelle ausgefüllt ist

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

Das Merkwürdige ist, dass ich die Daten wissen nicht bestehen aus zwei Gründen:

  • Mein Programm versucht, den Eintrag zu erstellen, wenn es nicht existiert, aber versucht, das gibt ein Fehler, dass die eindeutige Bedingung nicht befolgt wird.

  • Ausführen der Abfrage in meinem SQLite DB-Browser funktioniert gut:

The query returns a result, as it should.

ich sehr bezweifle, dass dies ein Problem mit unbestätigten Daten, da dies eine dateibasierte ist Datenbank, und das Öffnen dieser Datei mit einem Texteditor zeigt Instanzen der Benutzernamen in den Daten.

+1

"Mein Programm versucht, den Eintrag zu erstellen, wenn es nicht existiert, ** aber versucht, dass ein Fehler auftritt, dass die eindeutige Einschränkung nicht befolgt wird. **" - so bedeutet das, dass der Benutzer ** nicht ** existiert (oder sonst würde es nicht versuchen, es zu erzeugen, was zu der einzigartigen Beschränkungsverletzung führte), aber die eindeutige Einschränkung ist wahrscheinlich auf 'id' (anstelle von oder zusätzlich zu 'beam_id') –

Antwort

6

Schauen Sie genau auf, was Sie tun hier:

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

Ich glaube, es der Vertrag von Try-mit-Ressourcen ist in der try Klausel zu gewährleisten angegebene Ressource zu schließen, nachdem der Ausdruck Ausführung beendet. Ich glaube, dass die Ergebnismenge auch am Ende des try Blocks geschlossen wird, daher ruft next() false zurück, weil nichts da ist.

So wie ich den Code geschrieben haben würde, ist die User POJO innerhalb des try Blockes zu füllen, und gibt ein User Objekt stattdessen eine Ergebnismenge zurückzugeben:

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; 
} 

jetzt Ihre Trennung von Bedenken ist besser als Vor. Wenn etwas mit der Verbindung, der Ergebnismenge usw. schief geht, wird es im eigentlichen Code behandelt, der sich mit diesen Dingen beschäftigt. Im Falle einer Ausnahme oder eines anderen Fehlers wird ein null Benutzerobjekt zurückgegeben, und Sie sollten Ihren Code aktualisieren, um diese Möglichkeit zu umgehen.

+0

Das ist ein gutes Punkt, aber: Das Javadoc von 'ResultSet.next()' gibt an, dass es eine "SQLException" auslöst, wenn ein Datenbankzugriffsfehler auftritt oder diese Methode für eine geschlossene Ergebnismenge aufgerufen wird. Wenn das der Grund wäre, hätte das OP eine SQLException erhalten, nicht "false". Aber es ist möglich, dass der Treiber defekt ist und die JDBC-Spezifikation nicht korrekt implementiert. –

+0

@ErwinBolwidt Das ist mir auch durch den Kopf gegangen, aber nach dem, was ich gelesen habe, ist das Verhalten fahrerspezifisch. Wenn Sie eine bessere Erklärung dafür haben, dass _result set_ bei einer gültigen Abfrage leer ist, können Sie eine Antwort posten. –

+1

Dies hat es tatsächlich gelöst; Ich habe die Verwendung des ResultSet in den Try-with-Ressourcen verschachtelt, und es hat gut funktioniert. Danke für Ihre Hilfe! –

Verwandte Themen