使用Spring JdbcTemplate选择数据的最佳实践

64jmpszr  于 2023-04-19  发布在  Spring
关注(0)|答案(5)|浏览(136)

我想知道从表中选择记录的最佳实践是什么。我在下面提到了两种方法,我想知道哪一种是使用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);
    }
}

我很想知道正确的做法或其他最佳做法。

j8ag8udp

j8ag8udp1#

第一种方法无疑是最佳实践,因为在第二种方法中,您实际上应该只访问一次数据库,但却访问了两次,这可能会导致性能问题。
您需要做的是捕获异常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
}
euoag5mw

euoag5mw2#

我也遇到过类似的情况,但我发现使用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;
            }

    });

如果没有从数据库中找到结果,我已经为resultset设置了一个if条件并返回null引用。所以,我不需要尝试捕获代码并向数据库传递两个查询。
ResultSetExtractor的主要优点(在这个场景中)是使用ResultsetExtractor,您需要自己迭代结果集,比如在while循环中。
更多积分可以在这里找到here

s1ag04yj

s1ag04yj3#

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

NOW SOLUTION帮助了我:扩展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);
}

现在可以使用你的实现了,不要忘记检查它是否可以在spring版本更新中工作(恕我直言,这不太可能)

tp5buhyn

tp5buhyn4#

在查询中使用ifNull的更好的方法所以如果有null,那么你得到0。

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

使用这种方式,你可以得到默认为0,否则你的ID

ogsagwnx

ogsagwnx5#

如果表中可能没有数据,则按条件从表中获取行的最佳方法-将queryResultSetExtractor一起使用

fun findDailyReport(date: LocalDate): String? {
        val sql = """select * from reports_table where report_date = :date"""
        val map = MapSqlParameterSource("date", date)
        return jdbcTemplate.query(sql, map, ResultSetExtractor { rs ->
            if (rs.next()) {
                rs.getString("report")
            } else {
                log.warn("There is no daily report for the date: $date")
                null
            }
        })
    }

如果你需要检查一个表中是否存在一行,这里有一个很好的解决方案。在这种情况下,表中的所有记录都是唯一的:

fun checkReportExists(date: LocalDate): Boolean {
        val sql = """select 1 from reports_table where report_date = :date"""
        val map = MapSqlParameterSource("date", date)
        return jdbcTemplate.query(sql, map, ResultSetExtractor { rs -> rs.next() })!!
    }

第二解决方案:

fun checkReportExists(date: LocalDate): Boolean {
        val sql = """select count(1) from reports_table where report_date = :date"""
        val map = MapSqlParameterSource("date", date)
        return jdbcTemplate.queryForObject(sql, map, Int::class.java)!! > 0

最后一个解决方案:

fun checkReportExists(date: LocalDate): Boolean {
        val sql = """select exists(select 1 from reports_table where report_date = :date)"""
        val map = MapSqlParameterSource("date", date)
        return jdbcTemplate.queryForObject(sql, map, Boolean::class.java)!!

P.S.最后一个解决方案是fastest,用于检查行是否存在。

相关问题