首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

JdbcTemplate queryForObject 查詢單值陷阱:select count(*) 必須匹配返回類型

     編輯:Java 綜合教學

問題現象

使用 `JdbcTemplate.queryForObject(sql, params, Integer.class)` 執行統計查詢時,若 SQL 寫為 `SELECT * FROM ...` 而非 `SELECT COUNT(1) ...`,會拋出:

org.springframework.dao.IncorrectResultSizeDataAccessException: 
Incorrect result size: expected 1, actual N

或類型轉換異常:`Cannot convert value of type [com.xxx.Entity] to required type [java.lang.Integer]`。

根因

queryForObject 契約:

  1. **結果集必須恰好 1 行**;
  2. **該行必須恰好 1 列**,且可轉換為指定返回類型(如 `Integer`、`Long`、`String`)。

`SELECT *` 返回多列、多行,違反契約;`SELECT COUNT(1)` 返回單行單列數值,完美匹配。

正確代碼範本

public int countByCondition(String title, int mediaType, String status, 
                            String provider, String region, Date from, Date to) {
    StringBuilder sql = new StringBuilder("SELECT COUNT(1) FROM checkin_request WHERE 1=1 ");
    List<Object> params = new ArrayList<>();

    if (StringUtils.isNotEmpty(title)) {
        sql.append("AND title = ? ");
        params.add(title);
    }
    if (mediaType != -1) {
        sql.append("AND media_type = ? ");
        params.add(mediaType);
    }
    if (StringUtils.isNotEmpty(status)) {
        sql.append("AND current_status = ? ");
        params.add(status);
    }
    if (StringUtils.isNotEmpty(provider)) {
        sql.append("AND provider = ? ");
        params.add(provider);
    }
    if (StringUtils.isNotEmpty(region)) {
        sql.append("AND region = ? ");
        params.add(region);
    }
    if (from != null) {
        sql.append("AND create_time >= ? ");
        params.add(from);
    }
    if (to != null) {
        sql.append("AND create_time <= ? ");
        params.add(to);
    }

    return jdbcTemplate.queryForObject(sql.toString(), params.toArray(), Integer.class);
}

避坑清單

  1. 統計查詢永遠用 `COUNT(1)` / `COUNT(*)`**,別貪圖省事寫 `*`。
  2. 返回類型用 **基本類型包裝類** (`Integer`、`Long`)`,避免 null 拋 NPE;若可能為 0 行,用 `queryForObject(sql, params, Integer.class)` 會拋 `EmptyResultDataAccessException`,可改用 `queryForList` 手動判斷。
  3. 參數佔位符 `?` 數量與 `params` 大小**嚴格對應**。
  4. 動態 SQL 建議用 `StringBuilder` + `List` 組裝,最後 `toArray()`,防止 SQL 注入與拼接錯誤。

    擴展:查詢單行對象

    若需查詢單行映射為 POJO,請使用 `queryForObject(sql, params, new BeanPropertyRowMapper<>(Entity.class))`,前提同樣是 **SQL 必須保證只返回 1 行**。

    總結

    `queryForObject` = **單行單列** 或 **單行映射對象**。統計計數請堅持 `SELECT COUNT(1) ...`,類型匹配 `Integer`/`Long`,即可避開 90% 的誤用異常。

    1. 上一篇文章:
    2. 下一篇文章:
    Copyright © 程式碼之家 All Rights Reserved