Spring RowMapper接口如何工作? [英] How exactly work the Spring RowMapper interface?

查看:94
本文介绍了Spring RowMapper接口如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究Spring Core认证,并且对Spring如何处理JDBC查询有一些疑问:

I am studying for the Spring Core certification and I have some doubts about how Spring handle the JDBC queries:

所以我知道我可以根据希望获取的数据类型以多种方式从数据库表中获取数据:

So I know that I can obtain data from my DB tables in various ways depending on the type of data that I expect to obtain:

1)查询简单类型(作为int,long或String):我使用 jdbcTemplate queryForObject()方法strong>类,就像这样:

1) Query for simple type (as an int, a long or a String): I use the queryForObject() method of the jdbcTemplate class, something like it:

String sql = "SELECT count(*) FROM T_REWARD";
int rowsNumber = jdbcTemplate.queryForObject(sql, Integer.class);

因此,要获取一个简单的对象作为int值,我可以使用 queryForObject()方法,将 sql语句和我希望在其中接收的对象类型传递给它方法的输出.

So to obtain a simple object as an int value I use the queryForObject() method passing to it the sql stattment and the object type of I expect to receive in output from the method.

好的,这很简单,我认为还可以.

Ok, this is pretty simple and I think that it is ok.

2)查询放入地图对象中的整个表行:因此,如果我不需要单个值(该值可以位于特定对象的单个列中表的行或类似上例的内容),我可以通过以下方式使用 queryForMap(..) queryForList()方法:

2) Query for an entire table row putted into a Map object: so if I need no a single value (that could be into a single column of a specific row of a table or something like the preovious example) I can use the queryForMap(..) and the queryForList() methods, in these way:

2.1) queryForMap():如果我希望将单行放入单个Map对象(每个列的值为映射到我的地图中,例如:

2.1) queryForMap(): I use it if I expect a single row putted into a single Map object where each columns value is mapped into a of my Map, something like:

String sql = "select * from T_REWARD where CONFIRMATION_NUMBER = ?";
Map<String, Object> values = jdbcTemplate.queryForMap(sql,confirmation.getConfirmationNumber());

2.2) queryForList():如果希望更多行作为查询的输出,则可以使用它.因此,我将获得一个 Map对象列表,其中每个Map对象都代表查询输出的特定行.像这样的东西:

2.2) queryForList(): I use it if I expect more rows as output of my query. So I will obtain a list of Map objects where each Map object represent a specific row of the query output. Something like it:

String sql = "select * from PERSON";
return jdbcTemplate.queryForList(sql);

我认为这也很清楚.

然后,我可以使用JdbcTemplate将 ResultSet 映射到域对象中,这对我来说还不是很清楚.

Then I can map a ResultSet into a domain object using JdbcTemplate and this is not so clear for me.

在阅读文档时得知,JdbcTemplate使用回调方法支持此操作. 回调方法的确切含义是什么?

Reading the documentation is told that JdbcTemplate supports this using a callback approach. What exactly meand this callback approach ?

我知道Spring提供了 RowMapper界面,用于将ResultSet的单行映射到对象:

I know that Spring provides a RowMapper interface for mapping a single row of a ResultSet to an object:

public interface RowMapper<T> {
    T mapRow(ResultSet rs, int rowNum)
    throws SQLException;
}

并且我有以下使用此方法的示例示例,该示例使用一个新的RestaurandRowMapper对象作为 queryForObject()方法的返回对象:

and I have the following example compoese by this method that use a new RestaurandRowMapper object as returned object of a queryForObject() method:

public Restaurant findByMerchantNumber(String merchantNumber) {
    String sql = "select MERCHANT_NUMBER, NAME, BENEFIT_PERCENTAGE, BENEFIT_AVAILABILITY_POLICY from T_RESTAURANT where MERCHANT_NUMBER = ?";

    return jdbcTemplate.queryForObject(sql, new RestaurantRowMapper(), merchantNumber);

以及此内部类:

class RestaurantRowMapper implements RowMapper<Restaurant> {
    public Restaurant mapRow(ResultSet rs, int i) throws SQLException {
        return mapRestaurant(rs);
    }
}

使用此私有方法创建映射的

:

that use this private method to create the mapping:

private Restaurant mapRestaurant(ResultSet rs) throws SQLException {
    // get the row column data
    String name = rs.getString("NAME");
    String number = rs.getString("MERCHANT_NUMBER");
    Percentage benefitPercentage = Percentage.valueOf(rs.getString("BENEFIT_PERCENTAGE"));
    // map to the object
    Restaurant restaurant = new Restaurant(number, name);
    restaurant.setBenefitPercentage(benefitPercentage);
    restaurant.setBenefitAvailabilityPolicy(mapBenefitAvailabilityPolicy(rs));
    return restaurant;
}

所以我很难理解所有这些东西是如何工作的.

So I have some difficulties to understand how exactly work all this stuff.

我的主要疑问是以下几点:我知道我使用 queryForObject()方法将它期望作为输出参数的对象的类型作为输入参数传递给它(例如, Interger或Long).

My main doubt is the following one: I know that using the queryForObject() method I pass to it, as input parameter, the type of the object that I expect as output (for example an Interger or a Long).

如果我希望获得一个代表表的整行的域对象(例如,映射到 Restaurand对象的 Restaurant表的一行),我在想应该使用此对象(作为Restaurant对象),但在上一个示例中,我使用**行映射器对象而不是域对象:

If I expect to obtain a domain object that represent an entire row of a table (for example a row of the Restaurant table mapped into a Restaurand object) I'm thinking that I should use this object (as the Restaurant object) but in the previous example I use the **row mapper object instead the domain object:

return jdbcTemplate.queryForObject(sql, new RestaurantRowMapper(), merchantNumber);

此内部类仅包含 mapRow()方法,该方法返回预期的域对象

This inner class contain only the mapRow() method that return the expected domain object

class RestaurantRowMapper implements RowMapper<Restaurant> {
    public Restaurant mapRow(ResultSet rs, int i) throws SQLException {
        return mapRestaurant(rs);
    }
}

因此,我认为Spring会自动调用 mapRow()方法,该方法返回自动替换为queryForObject()方法的 Restaurand域对象 .但是我不确定它是否可以正常工作.

So I think that Spring automatically call the mapRow() method that return the Restaurand domain object that is automatically replaced into the queryForObject() method, or something like this. But I am not so sure about it exactly work.

我想念什么?您能解释一下后台到底发生了什么吗?

What am I missing? Can you explain me what exactly happen in the backstage?

Tnx

推荐答案

queryForObject方法如下所示:

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);
}

queryForObject方法在内部调用JdbcTemplate对象上的方法query. query方法定义为:

The queryForObject-method internally invokes the method query on the JdbcTemplate object. The query-method is defined as:

public <T> T query(
        PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
        throws DataAccessException;

如您所见,

ResultSetExtractor<T>传递给query方法,并且Spring方便地将您的RowMapper<T>转换为类型为new RowMapperResultSetExtractor<T>(rowMapper, 1)的对象. RowMapperResultSetExtractor是持有魔术钥匙的对象.调用对象时,它将按照以下代码片段重复所有行:

As you can see, a ResultSetExtractor<T> is passed to the query-method and Spring conveniently converts your RowMapper<T> to an object of type new RowMapperResultSetExtractor<T>(rowMapper, 1). The RowMapperResultSetExtractor is the object that holds the key to the magic. When the object is invoked it iterates all rows as per this snippet:

public List<T> extractData(ResultSet rs) throws SQLException {
    List<T> results = (this.rowsExpected > 0 ? new ArrayList<T>(this.rowsExpected) : new ArrayList<T>());
    int rowNum = 0;
    while (rs.next()) {
        results.add(this.rowMapper.mapRow(rs, rowNum++));
    }
    return results;
}

因此,原始的RowMapper是为每一行调用的回调.此外,正如您在此处看到的那样,将为所有匹配的结果调用RowMapper,并将您创建的Restaurant-对象添加到结果列表中.但是,由于仅查询一个对象,因此以下语句最终用于返回单个Restaurant对象.

So, your original RowMapper is the callback that is called for each row. Furthermore, as you can see here your RowMapper is invoked for all matching results and the Restaurant-object that you created is added to the result list. However, since you query for only one object the following statement is finally used to return your single Restaurant object.

        return DataAccessUtils.requiredSingleResult(results);

因此,总而言之:JdbcTempalte实现了策略模式(类似于模板方法模式).通过提供策略界面(RowMapper),您可以让JdbcTemplate为您完成繁重的工作(处理异常,连接等). RowMapper将每个匹配项映射为POJO(Restaurant),所有匹配项都被收集到List中.然后,方法queryForObject从该List中获取第一行,并将其返回给调用方.返回值基于RowMapper的通用类型,在您的情况下为Restaurant.

So, to sum up: JdbcTempalte implementes the Strategy Pattern (which is similar to the Template method pattern). And by providing a Strategy interface (the RowMapper) you can let JdbcTemplate do the heavy lifting for you (handling exceptions, connections etc). The RowMapper maps each hit as a POJO (the Restaurant) and all hits are collected to a List. The method queryForObject then takes the first row from that List and returns it to the caller. The return value is based on the generic type of the RowMapper which in your case is Restaurant.

这篇关于Spring RowMapper接口如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆