Лучший способ выбора данных с помощью Spring JdbcTemplate


Я хочу знать, что является наилучшей практики для выбора записей из таблицы. Я упомянул два метода ниже, из которых я хочу знать, какой из них лучше всего выбирать данные из таблицы с помощью Spring JdbcTemplate.

Первый пример

try {
    String sql = "SELECT id FROM tableName WHERE column_name = '" + coulmn value + "'";

    long id = jdbcTemplate.queryForObject(sql, Long.class);
} catch (Exception e) {
    if (log.isDebugEnabled()) {
        log.debug(e);
    }
}

Это приводит к следующему исключению:

Ожидаемый 1 фактический 0 как

Когда таблица не содержит никаких данных. Мой друг сказал, что это не лучшая практика для выбора данных. Он предположил, что приведенный ниже код является единственным оптимальным способом выбора данных.

Второй пример

try {
    String countQuery = "SELECT COUNT(id) FROM tableName";

    int count = jdbcTemplate.queryForInt(countQuery);
    if (count > 0) {
        String sql = "SELECT id FROM tableName WHERE column_name = '" + coulmn value + "'";

        long id = jdbcTemplate.queryForObject(sql, Long.class);
    }
} catch (Exception e) {
    if (log.isDebugEnabled()) {
        log.debug(e);
    }
}


Мне не терпится узнать правильную или любую другую лучшую практику.

4 14

4 ответа:

Безусловно, первый способ является лучшей практикой, потому что во втором случае вы дважды попадаете в базу данных, где на самом деле вы должны попасть в нее только один раз. Это может привести к проблемам с производительностью.

Что вам нужно сделать, так это поймать исключение EmptyResultDataAccessException и затем вернуть null обратно. Spring JDBC templates отбрасывает исключениеEmptyResultDataAccessException , если оно не находит данные в базе данных.

Ваш код должен выглядеть следующим образом.

try {
     sql = "SELECT id FROM tableNmae WHERE column_name ='"+ coulmn value+ "'";
     id= jdbcTemplate.queryForObject(sql, Long.class);
} 
catch (EmptyResultDataAccessException e) {
   if(log.isDebugEnabled()){
       log.debug(e);
   }
   return null
}

Лучше использовать ifNull в запросе , так что если есть null, то вы получаете 0 Напр..-

sql = "SELECT ifNull(id,0) FROM tableName WHERE column_name ='"+ coulmn value+ "'";

Используя этот способ, вы можете получить по умолчанию 0, иначе ваш Id

Я столкнулся с подобным сценарием и нашел более чистое решение при использовании ResultSetExtractor вместо RowMapper

jdbcTemplate.query(DBConstants.GET_VENDOR_DOCUMENT, new Object[]{vendorid}, rs -> {

            if(rs.next()){
                DocumentPojo vendorDoc = new DocumentPojo();
                vendorDoc.setRegDocument(rs.getString("registrationdoc"));
                vendorDoc.setMsmeLetter(rs.getString("msmeletter"));
                vendorDoc.setProprietorshipDocument(rs.getString("propertiershipformat"));
                vendorDoc.setNeftDocument(rs.getString("neftdoc"));
                vendorDoc.setPanCardDocument(rs.getString("pancard"));
                vendorDoc.setCancelledChequeDoc(rs.getString("cheque"));
                return vendorDoc;
            }
            else {
                return null;
            }

    });

Если результат не найден из базы данных, я поставил условие if для resultset и вернул нулевую ссылку. Таким образом, мне не нужно было пытаться поймать код и передать два запроса в базу данных.

Главным преимуществом ResultSetExtractor (в этом сценарии) является С ResultsetExtractor вам нужно будет перебирать результирующий набор самостоятельно, скажем в while петля.

Больше точек можно найти здесь здесь

Это исходный код метода queryForObject

@Nullable
public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws 
DataAccessException {
    List<T> results = this.query(sql, rowMapper);
    return DataAccessUtils.nullableSingleResult(results);
}

DataAccessUtils.nullableSingleResult

    @Nullable
public static <T> T nullableSingleResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
    if (CollectionUtils.isEmpty(results)) {
        throw new EmptyResultDataAccessException(1);
    } else if (results.size() > 1) {
        throw new IncorrectResultSizeDataAccessException(1, results.size());
    } else {
        return results.iterator().next();
    }
}

Не знаю, почему они бросают исключение на пустую коллекцию, вероятно, это просто копипаст из метода выше

    public static <T> T requiredSingleResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
    if (CollectionUtils.isEmpty(results)) {
        throw new EmptyResultDataAccessException(1);
    } else if (results.size() > 1) {
        throw new IncorrectResultSizeDataAccessException(1, results.size());
    } else {
        return results.iterator().next();
    }
}

Еще один шаг выше метода, который они должны были использовать

    @Nullable
public static <T> T singleResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
    if (CollectionUtils.isEmpty(results)) {
        return null;
    } else if (results.size() > 1) {
        throw new IncorrectResultSizeDataAccessException(1, results.size());
    } else {
        return results.iterator().next();
    }
}

Теперь решение помогло мне: Расширьте класс JdbcTemlate (вы можете построить его с введенным источником данных) и переопределить метод queryForObject:

    @Nullable
public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
    List<T> results = this.query(sql, rowMapper);
    return DataAccessUtils.singleResult(results);
}

Теперь работайте с вашим реализация Не забудьте проверить, работает ли он на весеннем обновлении версии (очень маловероятно, ИМХО)