web-dev-qa-db-ja.com

Spring JdbcTemplateを使用してデータを選択するベストプラクティス

テーブルからレコードを選択するためのベストプラクティスを教えてください。 Spring JdbcTemplate を使用してテーブルからデータを選択するのにどちらがベストプラクティスであるかを知りたいということから、以下の2つの方法について言及しました。

最初の例

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

テーブルにデータが含まれていない場合。私の友人は、これはデータを選択するためのベストプラクティスではないと言った。彼は、下記のコードがデータを選択するための唯一のベストプラクティスであることを提案しました。

2番目の例

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


正しいものまたは他のベストプラクティスを知りたいと思っています。

24

間違いなく、最初の方法がベストプラクティスです。2番目の方法では、実際にデータベースを1回だけヒットする必要がある場所に2回データベースをヒットするからです。これにより、パフォーマンスの問題が発生する可能性があります。

必要なことは、例外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
}
24

私は同様のシナリオに直面しており、RowMapperの代わりにResultSetExtractorを使用すると、よりクリーンなソリューションが見つかりました

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条件を設定し、null参照を返しました。そのため、コードをキャッチしてデータベースに2つのクエリを渡す必要はありませんでした。

(このシナリオでの)ResultSetExtractorの主な利点は、ResultsetExtractorで、whileループなどで結果セットを繰り返し処理する必要があることです

より多くのポイントはここにあります here

3
Ankit

クエリでifNullを使用するより良い方法したがって、nullがある場合は0を取得します。

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

この方法を使用すると、デフォルトの0として取得できます

3
Vikram

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

彼らが使用した方法のもう1つのステップ

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

NOWソリューションは私を助けてくれました: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);
}

今、あなたの実装で動作しますそれが春バージョンのアップデートで動作するかどうかを確認することを忘れないでください(私見はほとんどありません)

1
Anton Medvedev