在使用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 }