Лучшая практика для выбора данных с помощью 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);
    }
}


Я очень хочу знать правильную или любую другую лучшую практику.

Ответ 1

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

Что вам нужно сделать, это поймать исключение EmptyResultDataAccessException, а затем вернуть null обратно. Spring Шаблоны JDBC отбрасывают исключение 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
}

Ответ 2

Лучший способ использования ifNull в запросе, поэтому, если есть нуль, вы получаете 0 Например,.-

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

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

Ответ 3

Я столкнулся с похожим сценарием и нашел более чистое решение при использовании 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 для набора результатов и вернул нулевую ссылку. Поэтому мне не нужно было пытаться поймать код и передать два запроса в базу данных.

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

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

Ответ 4

Это исходный код метода 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 (вы можете создать его с использованием источника DataSource) и переопределить метод queryForObject:

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

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