使用 rowmapper 读取值时出现语法错误 SQL 异常

问题描述 投票:0回答:8

这是我的模型课

//Model

    public class CustomerData {

        private String locomotive_id;
        private String customer_name;
        private String road_number;
        private String locomotive_type_code;
        private String in_service_date;
        private String part_number;
        private String emission_tier_type;
        private String airbrake_type_code;
        private String lms_fleet;
        private String aar_road;
        private String locomotive_status_code;

        // Getters and Setters

这是我的 RowMapper 实现

//RowMapper

    public class CustomerDataResponseMapper implements RowMapper {

    @Override
    public Object mapRow(ResultSet rs, int count) throws SQLException {
        CustomerData customerData = new CustomerData();

        customerData.setLocomotive_id(rs.getString("locomotive_id"));
        customerData.setCustomer_name(rs.getString("customer_name"));
        customerData.setRoad_number(rs.getString("road_number"));
        customerData.setLocomotive_type_code(rs.getString("locomotive_type_code"));
        customerData.setIn_service_date(rs.getString("in_service_date"));
        customerData.setPart_number(rs.getString("part_number"));
        customerData.setEmission_tier_type(rs.getString("emission_tier_type"));
        customerData.setAirbrake_type_code(rs.getString("airbrake_type_code"));
        customerData.setLms_fleet(rs.getString("lms_fleet"));
        customerData.setAar_road(rs.getString("aar_road"));
        customerData.setLocomotive_status_code(rs.getString("locomotive_status_code"));

        return customerData;
    }

}

最后,我在这里得到了 DaoImpl 类

//DaoImpl
    public String getCustomersData(String locoId, String custName, String roadNumber) {
        CustomerData resultSet = null;
        String str = "";
        if (locoId != null && locoId.length() > 0 && !(locoId.equals("0"))) {
            str = "select   locomotive_id,customer_name,road_number,model_type as locomotive_type_code,to_char(in_service_date,'yyyy-mm-dd') as in_service_date,loco_part_number as part_number,    emission_tier_type as emission_tier_type, "
                    + "air_brake_type as airbrake_type_code,lms_fleet,aar_road,locomotive_status_code   from get_rdf_explorer.get_rdf_locomotive_detail  where locomotive_id = ?";
            resultSet = (CustomerData) jdbcTemplate.queryForObject(str, new CustomerDataResponseMapper(), locoId);
        } else if ((custName != null && custName.length() > 0)
                && (roadNumber != null && roadNumber.length() > 0 && roadNumber != "0")) {
            str = "select   locomotive_id,customer_name,road_number,model_type as locomotive_type_code,to_char(in_service_date,'yyyy-mm-dd') as in_service_date,loco_part_number as part_number,    emission_tier_type as emission_tier_type, "
                    + "air_brake_type as airbrake_type_code,lms_fleet,aar_road,locomotive_status_code   from get_rdf_explorer.get_rdf_locomotive_detail  where customer_name = ? and road_number= ?";
            resultSet = (CustomerData) jdbcTemplate.queryForObject(str, new CustomerDataResponseMapper(), custName, roadNumber);
        } else {
            str = "select distinct customer_name from get_rdf_explorer.get_rdf_locomotive_detail order by customer_name asc";
            resultSet = (CustomerData) jdbcTemplate.queryForObject(str, new CustomerDataResponseMapper());
        }
        return resultSet.toString();
    }

如何根据结果集中是否存在特定列有条件地从结果集中获取值。因为我没有通过查询一直获得所有列。

当结果集中不存在特定列时,我收到 SQL 错误语法异常。例如,当执行获取不同客户名称的第三个查询时,结果集中只有 customerName 存在,而没有其他列。

这确实是一个很大的帮助。提前非常感谢。

java spring jdbctemplate mapper
8个回答
6
投票

既然您已经有 3 个单独的查询,为什么不拥有 3 个单独的

RowMapper
,每个查询一个。您的查询“知道”它们返回哪些列,因此您可以轻松地为
RowMapper
创建这些类。

如果您确实想要高保真解决方案,您可以为公共部件创建抽象基

RowMapper
,并为查询指定的部件创建 3 个子类。


1
投票

您可以使用通用方法来调查

ResultSet
的列

@SuppressWarnings("unchecked")
public <T> T getColIfPresent(ResultSet rs, String columnName) throws SQLException {
    ResultSetMetaData metaData = rs.getMetaData();
    for (int i = 1; i <= metaData.getColumnCount(); i++) {
        if (columnName.equals(metaData.getColumnName(i))) {
            return (T) rs.getObject(columnName);
        }
    }
    return null;// not present
}

然后,在行映射器中。

customerData.setLocomotive_id(getColIfPresent(rs, "locomotive_id"));
...

这具有 O(n*m) 复杂度,其中 n - 检查的列数,m -

ResultSet
中返回的列数。

如果您选择忽略

SQLException
,至少将其记录在
DEBUG
TRACE
级别,以防出现不同的
SQLException
子类型,这样它就不会丢失。


1
投票

Santosh,一个快速的解决方法可以是在将标志提供给 jdbcTemplate 时将标志传递给 rowmapper。我已经做了很多次以避免多个行映射器。 resultSet = (CustomerData) jdbcTemplate.queryForObject(str, new CustomerDataResponseMapper(1), custName, roadNumber);

对于上述更改,您需要使用默认构造函数重载。然后你需要使用你的标志,即mapRow()方法中的实例变量来分别处理每种情况。


1
投票

您可以使用

BeanPropertyRowMapper
,它将直接映射目标类的字段名称。这是 javadoc

名称可以直接匹配,也可以通过使用“驼峰”大小写将用下划线分隔的部分的名称转换为相同的名称。因此,只要您想直接映射到类,您就可以使用它任何其他类。只需确保选定的字段保留在目标类中即可。以及 默认或无参数构造函数。

以下示例使用

CustomerData
 获取 
BeanPropertyRowMapper

RowMapper<CustomerData> mapper = new BeanPropertyRowMapper<>(CustomerData.class);
List<CustomerData> result = jdbc.query("your query string...", mapper, query_args...);

因此,您可以返回第一个对象或其他任何对象。


1
投票

我的建议是将您的

getCustomersData
分为三种不同的方法。如果您确实想忽略此建议,那么快速而肮脏的解决方案是保护 rowMapper 内的
rs.getString(...)
调用。像这样的东西:

try {
    customerData.setLocomotive_id(rs.getString("locomotive_id"));
} catch (SQLException e) {
    // ignore this exception. DO NOT TRY THIS AT HOME!
}

1
投票

您可以修改 SQL 以匹配您的映射器,而不是有条件地获取列,例如将其他字段设置为空字符串或

null
(我不记得
getString()
是否因 null 或其他原因而崩溃)。

例如,您的第三个查询如下所示:

select distinct  
    customer_name, null as "locomotive_id", '' as "road_number", 
    null as model_type, [etc.] 
from 
    get_rdf_explorer.get_rdf_locomotive_detail 
order by 
    customer_name asc

因此每个查询都将具有相同的列,您无需进行调整。如果您真的不想/无法更改 rowMapper(或者只想为该对象拥有一个),这就是解决方案。

但说实话,我会选择 ikketu 的解决方案。您应该为第三个查询创建一个单独的映射器(另外,它不会很复杂)。不使用 ORM 是一种选择,但无论如何你都会遇到冗余问题。我什至想补充一点,您应该分离代码中的一些逻辑,这个方法似乎在做不同的事情(业务逻辑取决于输入和数据库访问),这不是很清楚(在第三个 if 之后,创建一个像“ getdistinctName()”或其他东西)。


0
投票

如果列数不固定,那么您应该根据其实现使用

ColumnMapRowMapper
,即使您不需要创建单独的
RowMapper
具体类(即
CustomerDataResponseMapper
),您只需要传递
ColumnMapRowMapper
的实例查询如下:

ColumnMapRowMapper rowMapper = new ColumnMapRowMapper();
List<Map<String, Object>> customerDataList =  jdbcTemplate.query(sql,rowMapper, args);

现在您应该创建一种方法来操作此地图,例如

    private CustomerData fillCustomerDataFromMap(List<Map<String, Object>> customerDataList){
            CustomerData customerData = new CustomerData();

            for(Map<String, Object> map: customerDataList ){

               customerData.setColumn(map.get("columnName"));
               customerData.setColumn(map.get("columnName"));
               customerData.setColumn(map.get("columnName"));
               customerData.setColumn(map.get("columnName"));

.........
.........
.........
           }
        return customerData;
    }

这更具可读性,并且删除了样板代码,并且如果映射中不存在列名称,则不会抛出任何异常(如果映射中不存在列名称,它将简单地返回

null

参考

ColumnMapRowMapper

https://github.com/spring-projects/spring-framework/blob/master/spring-jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java


0
投票

根据您的查询逻辑,我发现在

get_rdf_explorer.get_rdf_locomotive_detail
中执行 sql 查询之前,有一些记录和 3 个获取必要(唯一)记录的选项:

  1. 作者:
    locomotive_id
  2. customer_name
    road_number
  3. 任何记录(所有记录必须具有相同的
    customer_name
    ,否则
    SQL distinct
    无任何条件返回超过1行)

因此,在第三个选项中,您可以获得所有属性等于

NULL
NOT NULL
customer_name
值的任意 1 条记录:

str = "select null as locomotive_id, customer_name, null as road_number,     
<other attributes> from get_rdf_explorer.get_rdf_locomotive_detail where 
rownum = 1";`
© www.soinside.com 2019 - 2024. All rights reserved.