在使用Spirng提供的JdbcTemplate中名為queryForObject API進行數據庫查詢時有時會拋出如下異常:
org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
(不正確的結果大小,預期是1,實際為0)
或者:
org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 2
(不正確的結果大小,預期是1,實際為2)
在解決這些異常之前,我們首先來看看queryForObject API的源代碼,假設我們調用的是queryForObject(String sql,Class requiredType)。
JdbcTemplate.class
1 public <T> T queryForObject(String sql, Class<T> requiredType) 2 throws DataAccessException 3 {return queryForObject(sql, getSingleColumnRowMapper(requiredType));} 4 5 public <T> T queryForObject(String sql, RowMapper<T> rowMapper) 6 throws DataAccessException { 7 List<T> results = query(sql, rowMapper); 8 return DataAccessUtils.requiredSingleResult(results); 9 } 10 11 public <T> List<T> query(String sql, RowMapper<T> rowMapper) 12 throws DataAccessException { 13 return query(sql, new RowMapperResultSetExtractor<T>(rowMapper)); 14 } 15 16 public <T> T query(final String sql, final ResultSetExtractor<T> rse) 17 throws DataAccessException { 18 Assert.notNull(sql, "SQL must not be null"); 19 Assert.notNull(rse, "ResultSetExtractor must not be null"); 20 if (logger.isDebugEnabled()) { 21 logger.debug("Executing SQL query [" + sql + "]"); 22 } 23 class QueryStatementCallback implements StatementCallback<T>, SqlProvider { 24 public T doInStatement(Statement stmt) throws SQLException { 25 ResultSet rs = null; 26 try { 27 rs = stmt.executeQuery(sql); 28 ResultSet rsToUse = rs; 29 if (nativeJdbcExtractor != null) { 30 rsToUse = nativeJdbcExtractor.getNativeResultSet(rs); 31 } 32 return rse.extractData(rsToUse); 33 } 34 finally { 35 JdbcUtils.closeResultSet(rs); 36 } 37 } 38 public String getSql() { 39 return sql; 40 } 41 } 42 return execute(new QueryStatementCallback()); 43 }
DataAccessUtil.class
1 public static <T> T requiredSingleResult(Collection<T> results) 2 throws IncorrectResultSizeDataAccessException { 3 int size = (results != null ? results.size() : 0); 4 if (size == 0) { 5 throw new EmptyResultDataAccessException(1); 6 } 7 if (results.size() > 1) { 8 throw new IncorrectResultSizeDataAccessException(1, size); 9 } 10 return results.iterator().next(); 11 }
通過閱讀源代碼,可以清楚地看到在DataAccessUtils.class中requiredSingleResult方法中,當結果集合的size為0或者大於1時,就會拋出以上兩個異常。
解決方法有兩個:
(1)通過修改數據庫:刪除數據庫中對應名稱(column)相同的記錄,留下只剩"1"條。
(2)通過更換方法:使用query方法返回list對象(該方法能返回所有查詢記錄)
1 public transient List query(String sql, RowMapper rowMapper, Object args[]) 2 throws DataAccessException 3 { 4 return (List)query(sql, args, ((ResultSetExtractor) (new RowMapperResultSetExtractor(rowMapper)))); 5 }
