JdbcTemplate针对数据查询提供了多个重载的模板方法,你可以根据需要选用不同的模板方法。 如果你的查询很简单,仅仅是传入相应SQL或者相关参数,然后取得一个单一的结果,那么你可以选择如下一组便利的模板方法:

int queryForInt(String sql)

int queryForInt(String sql, Object[] args)

long queryForLong(String sql)

long queryForLong(String sql, Object[] args)

Object queryForObject(String sql, Class requiredType)

Object queryForObject(String sql, Object[] args, Class requiredType)

Map queryForMap(String sql)

Map queryForMap(String sql, Object[] args)

比如说,你所查询的结果就包含一列数字型的结果,或者使用了SQL函数,或者其他单列的结果,我们就可以直接通过这组便利的模板方法进行查询: 
int age = jdbcTemplate.queryForInt("select age from customer where customerId=?",new Object[]{new Integer(100)});
...
long interval = jdbcTemplate.queryForLong("select count(customerId) from customer");
...
String customerName = jdbcTemplate.queryForString("select username from customer where customerId=110");
...
Map singleCustomer = jdbcTemplate.queryForMap("select * from customer limit 1");
...
queryForMap方法与其他方法不同之处在于,它的查询结果以java.util.Map的形式返回,Map的key对应所查询表的列名,Map的value当然就是对应key所在列的值啦。 当然了,你也看到了,这组模板方法主要用于单一结果的查询,使用的时候也请确保你的SQL查询所返回的结果是单一的,否则,JdbcTemplate将抛出org.springframework.dao.IncorrectResultSizeDataAccessException异常。 
如果查询的结果将返回多行,而你又不在乎他们是否拥有较强的类型约束,那么,以下模板方法可以帮助你:

List queryForList(String sql)

List queryForList(String sql, Object[] args)

queryForList方法根据传入的SQL以及相应的参数执行查询,将查询的结果以java.util.List的形式返回,返回的java.util.List中的每一个元素都是java.util.Map类型,分别对应结果集中的一行,Map的Key为每一列的列名,而Map的值就是当前行列名对应的值。 
好啦,如果这些还不足以满足你的查询需要,那么我们就更进一步,使用相应的Callback接口对查询结果的返回进行定制吧!

用于查询的回调接口定义主要有以下三种:

org.springframework.jdbc.core.ResultSetExtractor.  基本上属于JdbcTemplate内部使用的Callback接口,相对于下面两个Callback接口来说,ResultSetExtractor拥有更多的控制权,因为使用它,你需要自行处理ResultSet:

public interface ResultSetExtractor 
{
Object extractData(ResultSet rs) throws SQLException, DataAccessException;
}
在直接处理完ResultSet之后,你可以将处理后的结果以任何你想要的形式包装后返回。 
org.springframework.jdbc.core.RowCallbackHandler.  RowCallbackHandler相对于ResultSetExtractor来说,仅仅关注单行结果的处理,处理后的结果可以根据需要存放到当前RowCallbackHandler对象内或者使用JdbcTemplate的程序上下文中,当然,这个完全是看个人爱好了。 RowCallbackHandler的定义如下:

public interface RowCallbackHandler 
{
void processRow(ResultSet rs) throws SQLException;
}
org.springframework.jdbc.core.RowMapper.  ResultSetExtractor的精简版,功能类似于RowCallbackHandler,也只关注处理单行的结果,不过,处理后的结果会由ResultSetExtractor实现类进行组合。 RowMapper的接口定义如下:

public interface RowMapper 
{
Object mapRow(ResultSet rs, int rowNum) throws SQLException; 
}
为了说明这三种Callback接口的使用和相互之间的区别,我们暂且设定如下场景: 
数据库表customer中存在多行信息,对该表查询后,我们需要将每一行的顾客信息都映射到域对象Customer中,并以java.util.List的形式返回所有的查询结果。

现在,我们分别使用这三种Callback接口对customer表进行查询:

List customerList = (List)jdbcTemplate.query("select * from customer", new ResultSetExtractor(){

public Object extractData(ResultSet rs) throws SQLException,DataAccessException 
{
List customers = new ArrayList();
while(rs.next())
{
Customer customer = new Customer();
customer.setFirstName(rs.getString(1));
customer.setLastName(rs.getString(2));
...
customers.add(customer);
}
return customers;
}});
List customerList = jdbcTemplate.query("select * from customer", new RowMapper(){

public Object mapRow(ResultSet rs, int rowNumber) throws SQLException {
Customer customer = new Customer();
customer.setFirstName(rs.getString(1));
customer.setLastName(rs.getString(2));
...
return customer;
}});
final List customerList = new ArrayList();

jdbcTemplate.query("select * from customer", new RowCallbackHandler(){

public void processRow(ResultSet rs) throws SQLException {
Customer customer = new Customer();
customer.setFirstName(rs.getString(1));
customer.setLastName(rs.getString(2));
...
customerList.add(customer);
}});
如果你没有发现最大的差异在哪里,那么容我细表: 
使用三种Callback接口作为参数的query方法的返回值不同:

以ResultSetExtractor作为方法参数的query方法返回Object型结果,要使用查询结果,我们需要对其进行强制转型;

以RowMapper接口作为方法参数的query方法直接返回List型的结果;

以RowCallbackHandler作为方法参数的query方法,返回值为void;

使用ResultSetExtractor作为Callback接口处理查询结果,我们需要自己声明集合类,自己遍历ResultSet,自己根据每行数据组装Customer对象,自己将组装后的Customer对象添加到集合类中,方法最终只负责将组装完成的集合返回;

使用RowMapper比直接使用ResultSetExtractor要方便的多,只负责处理单行结果就行,现在,我们只需要将单行的结果组装后返回就行,剩下的工作,全部都是JdbcTemplate内部的事情了。 实际上,JdbcTemplae内部会使用一个ResultSetExtractor实现类来做其余的工作,毕竟,该做的工作还得有人做不是?!

JdbcTemplae内部使用的这个ResultSetExtractor实现类为org.springframework.jdbc.core.RowMapperResultSetExtractor, 它内部持有一个RowMapper实例的引用,当处理结果集的时候,会将单行数据的处理委派给其所持有的RowMapper实例,而其余工作它负责:

public Object extractData(ResultSet rs) throws SQLException {
List results = (this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList());
int rowNum = 0;
while (rs.next()) {
results.add(this.rowMapper.mapRow(rs, rowNum++));
}
return results;
}
这下应该清楚为啥RowMapper为啥就处理单行结果就能完成ResultSetExtractor颇费周折的工作了吧?! 
RowCallbackHandler虽然与RowMapper同是处理单行数据,不过,除了要处理单行结果,它还得负责最终结果的组装和获取工作,在这里我们是使用当前上下文声明的List取得最终查询结果, 不过,我们也可以单独声明一个RowCallbackHandler实现类,在其中声明相应的集合类,这样,我们可以通过该RowCallbackHandler实现类取得最终查询结果:

public class GenericRowCallbackHandler implements RowCallbackHandler {
private List collections = new ArrayList();

public void processRow(ResultSet rs) throws SQLException {
Customer customer = new Customer();
customer.setFirstName(rs.getString(1));
customer.setLastName(rs.getString(2));
...
collections.add(customer);
}

public List getResults()
{
return collections;
}
}

GenericRowCallbackHandler handler = new GenericRowCallbackHandler();
jdbcTemplate.query("select * from customer",handler());
List customerList = handler.getResults();
该使用方式是明了了,不过GenericRowCallbackHandler重用性不佳。 
RowCallbackHandler因为也是处理单行数据,所以,总得有人来做遍历ResultSet的工作,这个人其实也是一个ResultSetExtractor实现类, 它是JdbcTemplate一个内部静态类,名为RowCallbackHandlerResultSetExtractor,一看它的定义你就知道奥秘之所在了:

private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor {

private final RowCallbackHandler rch;

public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) {
this.rch = rch;
}

public Object extractData(ResultSet rs) throws SQLException {
while (rs.next()) {
this.rch.processRow(rs);
}
return null;
}
}
总的来说,内部工作归根结底是由ResultSetExtractor做了,RowCallbackHandler和RowMapper只是为了帮助我们简化使用上的操作而已。 所以,实际使用中,RowCallbackHandler和RowMapper才是我们最常用的选择。 
对于使用JdbcTemplate进行查询,基本就这些内容了,当然,如果你非要使用基于StatementCallback之类更底层的execute方法的话,那就是你个人说了算啦。 不过,要想知道JdbcTemplate中有关查询相关模板方法的更多信息,在实际使用中参考JdbcTemplate的javadoc就可以,当然,有IDE就更便捷了。

JdbcTemplate查询数据 三种callback之间的区别的更多相关文章

  1. 【jdbcTemplate】使用jdbcTemplate查询的三种回调

    用于查询的回调接口定义主要有以下三种: org.springframework.jdbc.core.ResultSetExtractor.  基本上属于JdbcTemplate内部使用的Callbac ...

  2. python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)

    昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...

  3. 【SQL】Oracle分页查询的三种方法

    [SQL]Oracle分页查询的三种方法 采用伪列 rownum 查询前10条记录 ? 1 2 3 4 5 6 7 8 9 10 11 [sql] select * from t_user t whe ...

  4. 使用 JdbcTemplate 查询数据时报错:列名无效(已解决)

    又犯了一个错误. 争取没有下次了. 就算再犯,也要知道去哪找答案. 所以,记录一下,以示警戒. 报错 使用 JdbcTemplate 查询数据时,出现异常: PreparedStatementCall ...

  5. 【转】Notepad++中Windows,Unix,Mac三种格式之间的转换

    原文网址:http://www.crifan.com/files/doc/docbook/rec_soft_npp/release/htmls/npp_func_windows_unix_mac.ht ...

  6. Oracle 数据库分页查询的三种方法

    一.Oracle 数据库分页查询的三种方法 1.简介 不能对 rownum 使用 >(大于或等于 1 的数值).>=(大于 1 的数值).=(不等于 1 的数值),否则无结果.所以直接用 ...

  7. (转)VMware虚拟机三种网络模式的区别及配置方法;

    我的一点实际经验理解桥接和NAT 桥接是虚拟机完全作为一个独立的地址接在局域网中,NAT是虚拟机依赖宿主主机地址转换的一种方式 例子我的虚拟机如果用桥接模式,连接外部网站如百度时会提示此pc没有装公司 ...

  8. png、jpg、gif三种图片格式的区别

    png.jpg.gif三种图片格式的区别   2014-06-17 为什么想整理这方面的类容,我觉得就像油画家要了解他的颜料和画布.雕塑家要了解他的石材一样,作为网页设计师也应该对图片格式的特性有一定 ...

  9. VMware 三种网络模式的区别

    VMware 三种网络模式的区别 VMware 三种网络模式的区别 我们首先说一下VMware的几个虚拟设备 VMnet0:用于虚拟桥接网络下的虚拟交换机 VMnet1:用于虚拟Host-Only网络 ...

随机推荐

  1. html5音频、视频

    1.插入一个视频:<video src="test.webm" width="800" height="600"></vi ...

  2. Discuz!NT 后台任意文件上传的源代码修补方法

    相关的漏洞介绍: http://www.wooyun.org/bugs/wooyun-2013-035199 Discuz!NT 管理后台可以自定义文件类型,从而造成任意文件上传,测试过程中 aspx ...

  3. HDU 5486 Difference of Clustering 图论

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5486 题意: 给你每个元素一开始所属的集合和最后所属的集合,问有多少次集合的分离操作,并操作和不变操 ...

  4. 为什么数据可以从pl/sql查出来而使用ado.net查询,结果却是空?

    1.背景 一条记录(如select * from A where a='1'),使用pl/sql作为条件可以查询出记录,但用ado.net sql查询结果却是空. 2.原因 a字段的数据类型的char ...

  5. HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?

    // test02.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...

  6. 【POJ】【2975】Nim

    博弈论 我哭……思路错误WA了6次?(好像还有手抖点错……) 本题是要求Nim游戏的第一步必胜策略有几种. 一开始我想:先全部异或起来得到ans,从每个比ans大的堆里取走ans个即可,答案如此累计… ...

  7. 20160729noip模拟赛zld

    首先显然有多少个奇数,就有多少个回文串是最优的(没有奇数时构造一个回文串 然后有了k个“核心”,把剩下的字符顺序安排到这些的两侧,最后最短的回文串长度就是答案 #include<map> ...

  8. JAVA数据源连接方式汇总

    最近在研究JAVA的数据源连接方式,学习的时候发现了一位同行写的文章,转载过来,留作记录! 一.问题引入 在java程序中,需要访问数据库,做增删改查等相关操作.如何访问数据库,做数据库的相关操作呢? ...

  9. Nginx正确记录post日志的方法

    Nginx正确记录post日志的方法 事实上可以很简单,这取决于把 access_log 放在哪个 location 里面. 一,放到包含fastcgi_pass或proxy_pass的Locatio ...

  10. 【设计模式六大原则1】单一职责原则(Single Responsibility Principle)

        http://blog.csdn.net/zhengzhb/article/category/926691/1 图片素材来源,java学习手册 ps.内容为自己整理   定义:不要存在多于一个 ...