2017-02-19 19 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 браузере работает просто отлично:

The query returns a result, as it should.

Я очень сомневаюсь, что это проблема с неподтвержденными данными, так как это база данных на основе файлов, и открытие этого файла текстовым редактором показывает экземпляры имен пользователей в данных.

+1

«Моя программа пытается создать запись, если она не существует **, но при попытке это дает ошибку, которой не соблюдается уникальное ограничение. **« Это значит, что пользователь делает ** не существует ** (иначе он не попытается создать его, что привело бы к уникальному нарушению ограничения), но единственное ограничение, скорее всего, будет на 'id' (вместо или в дополнение к' beam_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, потому что ничего не существует.

Как я написал бы ваш код для заполнения User POJO внутри try блока, и возвращает 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

Это хорошо point, но: javadoc 'ResultSet.next()' утверждает, что он генерирует «SQLException, если возникает ошибка доступа к базе данных или этот метод вызывается в закрытом результирующем наборе». Поэтому, если это была причина, OP должен был получить SQLException, а не 'false'. Но возможно, что драйвер сломан и не реализует спецификацию JDBC правильно. –

+0

@ErwinBolwidt Это тоже перешло мне в голову, но из того, что я прочитал, поведение зависит от конкретного драйвера. Если у вас есть лучшее объяснение того, что _result set_ пуст в действительном запросе, не стесняйтесь публиковать ответ. –

+1

Это, по сути, решило это; Я вложил использование ResultSet внутри try-with-resources, и это сработало отлично. Спасибо за вашу помощь! –