SpringBoot高级篇JdbcTemplate之数据查询上篇 讲了如何使用JdbcTemplate进行简单的查询操做,主要介绍了三种方法的调用姿式 queryForMap
, queryForList
, queryForObject
本篇则继续介绍剩下的两种方法使用说明java
环境依然借助前面一篇的配置,连接如: 190407-SpringBoot高级篇JdbcTemplate之数据插入使用姿式详解git
或者直接查看项目源码: github.com/liuyueyi/sp…github
咱们查询所用数据,正是前面一篇插入的结果,以下图spring
查询上篇中介绍的三种方法,返回的记录对应的结构要么是map,要么是经过RowMapper
进行结果封装;而queryForRowSet
方法的调用,返回的则是SqlRowSet
对象,这是一个集合,也就是说,能够查询多条记录sql
使用姿式也比较简单,以下app
public void queryForRowSet() {
String sql = "select * from money where id > 1 limit 2";
SqlRowSet result = jdbcTemplate.queryForRowSet(sql);
while (result.next()) {
MoneyPO moneyPO = new MoneyPO();
moneyPO.setId(result.getInt("id"));
moneyPO.setName(result.getString("name"));
moneyPO.setMoney(result.getInt("money"));
moneyPO.setDeleted(result.getBoolean("is_deleted"));
moneyPO.setCreated(result.getDate("create_at").getTime());
moneyPO.setUpdated(result.getDate("update_at").getTime());
System.out.println("QueryForRowSet by DirectSql: " + moneyPO);
}
}
复制代码
对于使用姿式而言与以前的区别不大,还有一种就是sql也支持使用占位方式,如ide
// 采用占位符方式查询
sql = "select * from money where id > ? limit ?";
result = jdbcTemplate.queryForRowSet(sql, 1, 2);
while (result.next()) {
MoneyPO moneyPO = new MoneyPO();
moneyPO.setId(result.getInt("id"));
moneyPO.setName(result.getString("name"));
moneyPO.setMoney(result.getInt("money"));
moneyPO.setDeleted(result.getBoolean("is_deleted"));
moneyPO.setCreated(result.getDate("create_at").getTime());
moneyPO.setUpdated(result.getDate("update_at").getTime());
System.out.println("QueryForRowSet by ? sql: " + moneyPO);
}
复制代码
重点关注下结果的处理,须要经过迭代器的方式进行数据遍历,获取每一列记录的值的方式和前面同样,能够经过序号的方式获取(序号从1开始),也能够经过制定列名方式(db列名)spring-boot
对于query方法的使用,从不一样的结果处理方式来看,划分了四种,下面逐一说明测试
queryByCallBack
这种回调方式,query方法不返回结果,可是须要传入一个回调对象,查询到结果以后,会自动调用ui
private void queryByCallBack() {
String sql = "select * from money where id > 1 limit 2";
// 这个是回调方式,不返回结果;一条记录回调一次
jdbcTemplate.query(sql, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
MoneyPO moneyPO = result2po(rs);
System.out.println("queryByCallBack: " + moneyPO);
}
});
}
复制代码
上面的实例代码中,能够看到回调方法中传入一个ResultSet对象,简单封装一个转换为PO的方法
private MoneyPO result2po(ResultSet result) throws SQLException {
MoneyPO moneyPO = new MoneyPO();
moneyPO.setId(result.getInt("id"));
moneyPO.setName(result.getString("name"));
moneyPO.setMoney(result.getInt("money"));
moneyPO.setDeleted(result.getBoolean("is_deleted"));
moneyPO.setCreated(result.getDate("create_at").getTime());
moneyPO.setUpdated(result.getDate("update_at").getTime());
return moneyPO;
}
复制代码
在后面的测试中,会看到上面会输出两行数据,也就是说
返回结果中每一条记录都执行一次上面的回调方法,即返回n条数据,上面回调执行n次
ResultSetExtractor
前面回调方式主要针对的是不关系返回结果,这里的则是将返回的结果,封装成咱们预期的对象,而后返回
private void queryByResultSet() {
String sql = "select * from money where id > 1 limit 2";
// extractData 接收的是批量的结果,所以能够理解为一次对全部的结果进行转换,能够和 RowMapper 方式进行对比
List<MoneyPO> result = jdbcTemplate.query(sql, new ResultSetExtractor<List<MoneyPO>>() {
@Override
public List<MoneyPO> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<MoneyPO> list = new ArrayList<>();
while (rs.next()) {
list.add(result2po(rs));
}
return list;
}
});
System.out.println("queryByResultSet: " + result);
}
复制代码
额外注意下上面你的使用,若是返回的是多条数据,注意泛型参数类型为List<?>
, 简单来讲这是一个对结果进行批量转换的使用场景
所以在上面的extractData
方法调用时,传入的是多条数据,须要本身进行迭代遍历,而不能像第一种那样使用
RowMapper
既然前面有批量处理,那固然也就有单行的转换方式了,以下
private void queryByRowMapper() {
String sql = "select * from money where id > 1 limit 2";
// 若是返回的是多条数据,会逐一的调用 mapRow方法,所以能够理解为单个记录的转换
List<MoneyPO> result = jdbcTemplate.query(sql, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
});
System.out.println("queryByRowMapper: " + result);
}
复制代码
在实际使用中,只须要记住RowMapper
方式传入的是单条记录,n次调用;而ResultSetExtractor
方式传入的所有的记录,1次调用
前面介绍的几种都是直接写sql,这固然不是推荐的写法,更常见的是占位sql,经过传参替换,这类的使用前一篇博文介绍得比较多了,这里给出一个简单的演示
private void queryByPlaceHolder() {
String sql = "select * from money where id > ? limit ?";
// 占位方式,在最后面加上实际的sql参数,第二个参数也能够换成 ResultSetExtractor
List<MoneyPO> result = jdbcTemplate.query(sql, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
}, 1, 2);
System.out.println("queryByPlaceHolder: " + result);
}
复制代码
PreparedStatement
方式在插入记录的时候,PreparedStatement
这个咱们用得不少,特别是在要求返回主键id时,离不开它了, 在实际的查询中,也是能够这么用的,特别是在使用PreparedStatementCreator
,咱们能够设置查询的db链接参数
private void queryByPreparedStatement() {
// 使用 PreparedStatementCreator查询,主要是能够设置链接相关参数, 如设置为只读
List<MoneyPO> result = jdbcTemplate.query(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
con.setReadOnly(true);
PreparedStatement statement = con.prepareStatement("select * from money where id > ? limit ?");
// 表示 id > 1
statement.setInt(1, 1);
// 表示 limit 2
statement.setInt(2, 2);
return statement;
}
}, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
});
System.out.println("queryByPreparedStatement: " + result);
}
复制代码
上面是一个典型的使用case,固然在实际使用JdbcTemplate时,基本不这么玩
前面一篇查询中,在单个查询中若是没有结果命中sql,会抛出异常,那么这里呢?
private void queryNoRecord() {
// 没有命中的状况下,会怎样
List<MoneyPO> result = jdbcTemplate
.query("select * from money where id > ? limit ?", new Object[]{100, 2}, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
});
System.out.println("queryNoRecord: " + result);
}
复制代码
从后面的输出结果会看出,没有记录命中时,并无什么关系,上面会返回一个空集合
接下来测试下上面的输出
package com.git.hui.boot.jdbc;
import com.git.hui.boot.jdbc.insert.InsertService;
import com.git.hui.boot.jdbc.query.QueryService;
import com.git.hui.boot.jdbc.query.QueryServiceV2;
import com.git.hui.boot.jdbc.update.UpdateService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/** * Created by @author yihui in 11:04 19/4/4. */
@SpringBootApplication
public class Application {
private QueryServiceV2 queryServiceV2;
public Application(QueryServiceV2 queryServiceV2) {
this.queryServiceV2 = queryServiceV2;
queryTest2();
}
public void queryTest2() {
// 第三个调用
queryServiceV2.queryForRowSet();
queryServiceV2.query();
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
复制代码
上面执行输出结果以下
本文主要介绍了另外两种查询姿式, queryForRowSet
与 query
queryForRowSet
SqlRowSet
对象,须要遍历获取全部的结果query
ResultSetExtractor
RowMapper
PreparedStatementCreator
来建立PreparedStatement
方式处理相关博文
尽信书则不如,以上内容,纯属一家之言,因我的能力有限,不免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激