本篇文章将遇到的一些jdbcTemplate方法,出现问题的地方做记录
Object queryForObject(String sql, Object[] args, Class requiredType)
这个重载方法,requiredType是一个单列的返回类型,select中只能有一个column
代码分析
public Object queryForObject(String sql, Object args[], Class requiredType)throws DataAccessException {
return queryForObject(sql, args, getSingleColumnRowMapper(requiredType));
}
//getSingleColumnRowMapper就可以说明问题
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException
{
ResultSetMetaData rsmd;
Object result;
rsmd = rs.getMetaData();
int nrOfColumns = rsmd.getColumnCount();
if(nrOfColumns != 1) //不是单列抛出异常
throw new IncorrectResultSetColumnCountException(1, nrOfColumns);
result = getColumnValue(rs, 1, requiredType);
if(result == null || requiredType == null || requiredType.isInstance(result))
break MISSING_BLOCK_LABEL_136;
return convertValueToRequiredType(result, requiredType);
IllegalArgumentException ex;
ex;
throw new TypeMismatchDataAccessException((new StringBuilder()).append("Type mismatch affecting row number ").append(rowNum).append(" and column type '").append(rsmd.getColumnTypeName(1)).append("': ").append(ex.getMessage()).toString());
return result;
}
如何解决? 可以使用框架提供的BeanPropertyRowMapper,自己会将rs中的column值反射到指定的映射对象User中
public User findUser(RegisterDTO dto) {
String sql = "select t.id as userid ,t.displayname from user1 t where t.displayname = ? ";
Object args[] = new Object[]{dto.getDisplayname()};
return (User) jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(User.class),args);
}
或者可以自己使用匿名内部类,新建一个RowMapper,自定义返回
queryForObject与queryForMap返回唯一值,且一定要有值,如果没有值的话,抛出异常org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
代码分析
@Override
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
List<T> results = query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));
return DataAccessUtils.requiredSingleResult(results);
}
DataAccessUtils.requiredSingleResult(results)
public static <T> T requiredSingleResult(Collection<T> results) throws IncorrectResultSizeDataAccessException {
int size = (results != null ? results.size() : 0);
if (size == 0) { //查询的结果为0,抛异常
throw new EmptyResultDataAccessException(1);
}
if (results.size() > 1) { //结果数量1抛异常
throw new IncorrectResultSizeDataAccessException(1, size);
}
return results.iterator().next();
}
解决办法,只能在调用queryForObject的时候捕捉这个异常了。
代码如下
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public User findUser(RegisterDTO dto) {
String sql = "select t.id as userid ,t.displayname from user1 t where t.displayname = ? ";
Object args[] = new Object[]{dto.getDisplayname()};
//return (User) jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(User.class),args);
try {
return (User) jdbcTemplate.queryForObject(sql, new RowMapper(){
@Override
public Object mapRow(ResultSet resultset, int i) throws SQLException {
User user = new User();
user.setDisplayname(resultset.getString("displayname"));
return user;
}
},args);
}catch(EmptyResultDataAccessException e) {
return null;
}
}
这代码看起来有点蛋疼,queryForObject用起来也有点蛋疼
public List queryForList(String sql, Class elementType)
throws DataAccessException
{
return query(sql, getSingleColumnRowMapper(elementType));
}
像这里,指定了elementType,都是使用SingleColumnRowMapper,返回单列,解决办法,和queryForObject一样
未完待续