当前位置: 首页 > 面试题库 >

Spring RowMapper接口如何工作?

秦彦君
2023-03-14
问题内容

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

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

1)查询 简单类型* (如int,long或String):我使用 jdbcTemplate 类的 queryForObject()
方法,类似这样:
*

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

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

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

2)查询放入 Map* 对象的 整个表行 :因此,如果我不需要单个值(该值可以在表的特定行的单个列中,或者在类似上一示例中),则可以使用
queryForMap( ..)queryForList() 方法,方法如下:
*

2.1) queryForMap() :如果我希望将 一行 放入一个 Map对象中
,其中每个列的值都映射到我的Map中,则可以使用它,例如:

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

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

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

我认为这也很清楚。

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

阅读文档可得知JdbcTemplate使用 回调方法 支持此功能。 回调方法的 确切含义是什么?

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

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

并且我有以下使用此方法的示例组合,它们使用新的RestaurandRowMapper对象作为 queryForObject() 方法的返回对象:

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

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

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

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

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

如果我希望获得一个代表表的整个行的域对象(例如,将 餐厅表 的一行映射到
Restaurand对象),则我认为我应该使用该对象(作为Restaurant对象),但是在前面的示例中,我使用 row mapper对象
而不是
domain对象** :

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

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

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

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

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

特纳克斯


问题答案:

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-method内部调用该方法query的上JdbcTemplate对象。所述query-method定义为:

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

如您所见,a
ResultSetExtractor<T>传递给query-method,Spring方便地将您转换RowMapper<T>为type对象new RowMapperResultSetExtractor<T>(rowMapper, 1)。该RowMapperResultSetExtractor是保存的关键法宝的对象。调用对象时,它将按照以下代码片段迭代所有行:

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您创建的-
object添加到结果列表中。但是,由于仅查询 一个 对象,因此以下语句最终用于返回单个Restaurant对象。

        return DataAccessUtils.requiredSingleResult(results);

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



 类似资料:
  • 问题内容: 可用于测试对象是给定类的直接实例还是后代实例。即使接口不能像类一样实例化,也可以与接口一起使用。谁能解释工作原理? 问题答案: 首先,我们可以存储这样实现特定功能的类。 即,任何实现特定接口的运行时实例都将通过测试 编辑 和输出 @RohitJain 您可以通过使用这样的匿名内部类来创建接口的实例 然后使用类似的运算符测试实例的类型为interface 结果为“ true”

  • 我正在学习Spring核心认证,我对Spring如何处理JDBC查询有一些疑问: 因此,为了获得一个作为int值的简单对象,我使用queryForObject()方法,将sql stattment和我期望从该方法接收的对象类型传递给它。 好的,这很简单,我认为这是可以的。 2)查询输入到Map对象中的整个表行:因此,如果我不需要单个值(可以在表的特定行的单个列中,或者类似前面的示例),我可以使用q

  • 问题内容: 据我所知,我们无法实例化接口,那么这是怎么发生的呢? 问题答案: 您无法实例化接口,但是可以为实现该接口的类的对象提供接口的引用,因此在代码中,您正在实现接口并创建该类的对象并提供该类的引用。

  • 最近我正在学习Java8个特性,所以我从lambda表达式开始,然后我遇到了Java流API,现在我正在尝试围绕流API中的方法,它们是如何工作的? 我对lambda表达式的理解是,如果我们想将lambda表达式传递给该方法,那么我们需要使用单个未实现的方法(Java 8接口可以有默认实现)创建一个与lambda表达式的签名匹配的接口。然后,传递lambda表达式的方法可以通过调用接口方法来执行l

  • 问题内容: 我知道什么是标记界面以及何时需要使用它。我仍然不清楚一个问题。如果标记接口没有任何方法或主体,那么它在运行时如何工作? 问题答案: 标识接口,可以进行分类