7 java spring spring-jdbc jdbctemplate
我正在学习Spring Core认证,我对Spring如何处理JDBC查询有些怀疑:
所以我知道我可以通过各种方式从我的数据库表中获取数据,具体取决于我希望获得的数据类型:
1)查询简单类型(作为int,long或String):我使用jdbcTemplate类的queryForObject()方法,类似于:
String sql = "SELECT count(*) FROM T_REWARD";
int rowsNumber = jdbcTemplate.queryForObject(sql, Integer.class);
Run Code Online (Sandbox Code Playgroud)
因此,为了获得一个简单的对象作为int值,我使用queryForObject()方法向它传递sql stattment和我期望在该方法的输出中接收的对象类型.
好的,这很简单,我认为没问题.
2)查询放入Map对象的整个表行:所以如果我不需要单个值(可能是某个表的特定行的单个列或类似于preovious示例的东西),我可以使用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());
Run Code Online (Sandbox Code Playgroud)
2.2)queryForList():如果我希望有更多行作为我的查询输出,我会使用它.因此,我将获得一个Map对象列表,其中每个Map对象代表查询输出的特定行.喜欢它的东西:
String sql = “select * from PERSON”;
return jdbcTemplate.queryForList(sql);
Run Code Online (Sandbox Code Playgroud)
我认为这也很清楚.
然后我可以使用JdbcTemplate 将ResultSet映射到域对象,这对我来说并不是那么清楚.
阅读文档告诉JdbcTemplate使用回调方法支持这一点.究竟是什么以及这种回调方式?
我知道Spring提供了一个RowMapper接口,用于将ResultSet的单行映射到对象:
public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNum)
throws SQLException;
}
Run Code Online (Sandbox Code Playgroud)
我有以下示例compoese这个方法使用一个新的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);
Run Code Online (Sandbox Code Playgroud)
而这个内部阶级:
class RestaurantRowMapper implements RowMapper<Restaurant> {
public Restaurant mapRow(ResultSet rs, int i) throws SQLException {
return mapRestaurant(rs);
}
}
Run Code Online (Sandbox Code Playgroud)
使用此私有方法创建映射:
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;
}
Run Code Online (Sandbox Code Playgroud)
所以我有一些困难要理解这些东西究竟是如何工作的.
我主要怀疑的是:我知道使用queryForObject()方法,我将其作为输入参数传递给它,我期望作为输出的对象的类型(例如,Interger或Long).
如果我希望获得一个表示表的整行的域对象(例如,映射到Restaurand对象的Restaurant表的一行)我认为我应该使用这个对象(作为Restaurant对象)但是在前面的例子我使用**行映射器对象而不是域对象:
return jdbcTemplate.queryForObject(sql, new RestaurantRowMapper(), merchantNumber);
Run Code Online (Sandbox Code Playgroud)
此内部类仅包含返回预期域对象的mapRow()方法
class RestaurantRowMapper implements RowMapper<Restaurant> {
public Restaurant mapRow(ResultSet rs, int i) throws SQLException {
return mapRestaurant(rs);
}
}
Run Code Online (Sandbox Code Playgroud)
所以我认为Spring会自动调用mapRow()方法,该方法返回自动替换为queryForObject()方法的Restaurand域对象,或类似的东西.但我不确定它究竟是否奏效.
我错过了什么?你能解释一下后台到底发生了什么吗?
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);
}
Run Code Online (Sandbox Code Playgroud)
所述queryForObject-method内部调用该方法query的上JdbcTemplate对象.所述query-method定义为:
public <T> T query(
PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
throws DataAccessException;
Run Code Online (Sandbox Code Playgroud)
如您所见,a ResultSetExtractor<T>传递给query-method,Spring可以方便地将您转换RowMapper<T>为类型的对象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;
}
Run Code Online (Sandbox Code Playgroud)
所以,你的原始版本RowMapper是为每一行调用的回调.此外,正如您在此处所见,您RowMapper将调用所有匹配结果,并将Restaurant您创建的对象添加到结果列表中.但是,由于您只查询一个对象,因此最后使用以下语句返回单个Restaurant对象.
return DataAccessUtils.requiredSingleResult(results);
Run Code Online (Sandbox Code Playgroud)
因此,总结一下:JdbcTempalte实现策略模式(类似于模板方法模式).通过提供一个策略界面(the RowMapper),您可以JdbcTemplate为您做繁重的工作(处理异常,连接等).在RowMapper每打一个POJO(地图Restaurant)和所有命中收集到List.queryForObject然后该方法从该行获取第一行List并将其返回给调用者.返回值是基于通用型的RowMapper而你的情况是Restaurant.
| 归档时间: |
|
| 查看次数: |
29349 次 |
| 最近记录: |