Saltar al contenido

Consulta jdbctemplate para cadena: EmptyResultDataAccessException: Tamaño de resultado incorrecto: esperado 1, real 0

Solución:

En JdbcTemplate, queryForInt, queryForLong, queryForObject Todos estos métodos esperan que la consulta ejecutada devuelva una y solo una fila. Si no obtiene filas o más de una fila, resultará en IncorrectResultSizeDataAccessException . Ahora, la forma correcta es no detectar esta excepción o EmptyResultDataAccessException, pero asegúrese de que la consulta que está utilizando devuelva solo una fila. Si no es posible, utilice query método en su lugar.

List<String> strLst  = getJdbcTemplate().query(sql,new RowMapper {

  public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
        return rs.getString(1);
  }

});

if ( strLst.isEmpty() ){
  return null;
}else if ( strLst.size() == 1 ) { // list contains exactly 1 element
  return strLst.get(0);
}else{  // list contains more than 1 elements
  //your wish, you can either throw the exception or return 1st element.    
}

También puede utilizar un ResultSetExtractor en lugar de un RowMapper. Ambos son tan fáciles como el otro, la única diferencia es que llamas ResultSet.next().

public String test() {
    String sql = "select ID_NMB_SRZ from codb_owner.TR_LTM_SLS_RTN "
                 + " where id_str_rt="999" and ID_NMB_SRZ = '60230009999999'";
    return jdbc.query(sql, new ResultSetExtractor<String>() {
        @Override
        public String extractData(ResultSet rs) throws SQLException,
                                                       DataAccessException {
            return rs.next() ? rs.getString("ID_NMB_SRZ") : null;
        }
    });
}

los ResultSetExtractor tiene el beneficio adicional de que puede manejar todos los casos en los que hay más de una fila o no se devuelven filas.

ACTUALIZAR: Varios años después y tengo algunos trucos para compartir. JdbcTemplate funciona magníficamente con java 8 lambdas para las que están diseñados los siguientes ejemplos, pero puede usar fácilmente una clase estática para lograr lo mismo.

Si bien la pregunta es sobre tipos simples, estos ejemplos sirven como guía para el caso común de extracción de objetos de dominio.

Antes que nada. Supongamos que tiene un objeto de cuenta con dos propiedades para simplificar Account(Long id, String name). Es probable que desee tener un RowMapper para este objeto de dominio.

private static final RowMapper<Account> MAPPER_ACCOUNT =
        (rs, i) -> new Account(rs.getLong("ID"),
                               rs.getString("NAME"));

Ahora puede usar este mapeador directamente dentro de un método para mapear Account objetos de dominio de una consulta (jt es un JdbcTemplate ejemplo).

public List<Account> getAccounts() {
    return jt.query(SELECT_ACCOUNT, MAPPER_ACCOUNT);
}

Genial, pero ahora queremos nuestro problema original y usamos mi solución original reutilizando el RowMapper para realizar el mapeo por nosotros.

public Account getAccount(long id) {
    return jt.query(
            SELECT_ACCOUNT,
            rs -> rs.next() ? MAPPER_ACCOUNT.mapRow(rs, 1) : null,
            id);
}

Genial, pero este es un patrón que puede y deseará repetir. Entonces puede crear un método de fábrica genérico para crear un nuevo ResultSetExtractor para la tarea.

public static <T> ResultSetExtractor singletonExtractor(
        RowMapper<? extends T> mapper) {
    return rs -> rs.next() ? mapper.mapRow(rs, 1) : null;
}

Creando un ResultSetExtractor ahora se vuelve trivial.

private static final ResultSetExtractor<Account> EXTRACTOR_ACCOUNT =
        singletonExtractor(MAPPER_ACCOUNT);

public Account getAccount(long id) {
    return jt.query(SELECT_ACCOUNT, EXTRACTOR_ACCOUNT, id);
}

Espero que esto ayude a demostrar que ahora puede combinar partes con bastante facilidad de una manera poderosa para simplificar su dominio.

ACTUALIZACIÓN 2: Se combina con un Opcional para valores opcionales en lugar de nulo.

public static <T> ResultSetExtractor<Optional<T>> singletonOptionalExtractor(
        RowMapper<? extends T> mapper) {
    return rs -> rs.next() ? Optional.of(mapper.mapRow(rs, 1)) : Optional.empty();
}

Que ahora, cuando se usa, podría tener lo siguiente:

private static final ResultSetExtractor<Optional<Double>> EXTRACTOR_DISCOUNT =
        singletonOptionalExtractor(MAPPER_DISCOUNT);

public double getDiscount(long accountId) {
    return jt.query(SELECT_DISCOUNT, EXTRACTOR_DISCOUNT, accountId)
            .orElse(0.0);
}

Esa no es una buena solución porque depende de las excepciones para controlar el flujo. En su solución, es normal obtener excepciones, es normal tenerlas en el registro.

public String test() {
    String sql = "select ID_NMB_SRZ from codb_owner.TR_LTM_SLS_RTN where id_str_rt="999" and ID_NMB_SRZ = '60230009999999'";
    List<String> certs = jdbc.queryForList(sql, String.class); 
    if (certs.isEmpty()) {
        return null;
    } else {
        return certs.get(0);
    }
}
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *