跳到主要内容

查询

JdbcTemplate 提供多种读取结果集的 API;方法名称并不会把连接或数据库操作强制设为只读。大多数接口接受 SQL 字符串和参数(对象或数组),返回由结果集构建的对象;部分接口支持回调/映射器以自定义处理过程。

先选方法​

你的目标推荐方法
查询多行 Bean 或 MapqueryForList
查询单行 BeanqueryForObject
查询单行 MapqueryForMap
查询单个值,例如 count、sumqueryForLong、queryForObject
查询两列并转成 MapqueryForPairs
自定义每行如何映射RowMapper
自定义整个 ResultSet 如何处理ResultSetExtractor
大结果集逐行处理RowCallbackHandler 或流式查询

查询结果集​

查询一个对象或 Map 集合并返回。

// 原始 SQL(独立示例)
{
List<User> users = jdbc.queryForList(
"select * from users where id > 2", User.class);
}

// 位置参数(独立示例)
{
Object[] args = new Object[]{ 2 };
List<User> result = jdbc.queryForList(
"select * from users where id > ?", args, User.class);
}

// 名称参数(独立示例)
{
Map<String, Object> namedArgs = CollectionUtils.asMap("id", 2);
List<User> result = jdbc.queryForList(
"select * from users where id > :id", namedArgs, User.class);
}

查询对象​

返回映射到指定类型的单行。常见场景:聚合查询、主键查找。无结果时返回 null,多行时抛出异常;接收可能为空的标量时使用包装类型。

// 原始 SQL(独立示例)
{
User user = jdbc.queryForObject(
"select * from users where id = 2", User.class);
}

// 位置参数(独立示例)
{
Object[] args = new Object[]{ 2 };
User user = jdbc.queryForObject(
"select * from users where id = ?", args, User.class);
}

// 名称参数(独立示例)
{
Map<String, Object> namedArgs = CollectionUtils.asMap("id", 2);
User user = jdbc.queryForObject(
"select * from users where id = :id", namedArgs, User.class);
}

查询键值对​

键值对是将查询到的结果集将第一个列和第二个列分别作为 Map 的 Key 和 Value 将整个结果集存储为一个 Map 类型。

// 原始 SQL(独立示例)
{
Map<Long, String> userMap = jdbc.queryForPairs(
"select uid, name from user where age > 2", Long.class, String.class);
}

// 位置参数(独立示例)
{
Object[] args = new Object[]{ 2 };
Map<Long, String> userMap = jdbc.queryForPairs(
"select uid, name from user where age > ?", Long.class, String.class, args);
}

// 名称参数(独立示例)
{
Map<String, Object> namedArgs = CollectionUtils.asMap("age", 2);
Map<Long, String> userMap = jdbc.queryForPairs(
"select uid, name from user where age > :age", Long.class, String.class, namedArgs);
}

查询值​

查询值区别于查询对象是在于值是可映射的最小类型单元,可以是 TypeHandlerRegistry 注册器中的类型。如:String、Int、Date 等。查询值通常有两种情况:

  • 查询值列表,例如获取符合条件的对象 ID 集合。
  • 查询聚合汇总信息,例如统计总数,求平均值等。
// 原始 SQL(独立示例)
{
long count = jdbc.queryForLong(
"select count(*) from user where age > 2");
}

// 位置参数(独立示例)
{
Object[] args = new Object[]{ 2 };
long count = jdbc.queryForLong(
"select count(*) from user where age > ?", args);
}

// 名称参数(独立示例)
{
Map<String, Object> namedArgs = CollectionUtils.asMap("age", 2);
long count = jdbc.queryForLong(
"select count(*) from user where age > :age", namedArgs);
}
提示
  • jdbc.queryForObject("select count(*) from users", Integer.class); // 具有等效能力

结果接收方式​

这些示例覆盖最常见的返回形态。需要控制结果映射过程时,可以按下表选择;详细机制见 接收结果。

目标推荐方式详细说明
每行转成一个对象RowMapperRowMapper
不定义实体类,直接接收列名和值List<Map<String,Object>>List/Map
大结果集逐行消费,不在内存中收集RowCallbackHandlerRowCallbackHandler
自己接管整个 ResultSet 遍历过程ResultSetExtractorResultSetExtractor
单列值的序列化/反序列化TypeHandler类型处理

使用 ResultSetExtractor​

User user = jdbc.query(
"select * from users where id = ?",
new Object[]{ 1 },
(ResultSetExtractor<User>) rs -> {
if (!rs.next()) {
return null;
}

User u = new User();
u.setId(rs.getLong("id"));
u.setName(rs.getString("name"));
return u;
}
);

逐行处理​

回调避免应用收集完整结果集,但是否按需从服务端读取,还取决于 JDBC 驱动、fetchSize 和连接配置。

RowCallbackHandler handler = (rs, rowNum) -> {
// 逐行处理,不收集为 List
};

jdbc.query("select * from users where age > ?", new Object[]{ 18 }, handler);

Map 大小写敏感性​

默认情况下,Map 结果的列名 key 大小写不敏感。不同数据库返回列名大小写可能不同,例如 Oracle 常见大写、MySQL 常见小写。需要严格区分大小写时,参考 List/Map 接收数据。

查询参数说明​

在查询相关 API 中,参数统一按 Object 传递,可支持的类型如下:

  • 位置参数(多个值放入数组或集合,方法接收的是 Object args,不是可变参数)
    • 数组、Collection、TypeRegistry 中注册的类型
  • 名称化参数
    • Map、实体 Bean、SqlArg(名称会固定为 arg0)
  • 自定义,完全自定义参数设置逻辑,适合需要手动类型控制的场景。
  • 动态 SQL
    • 使用 规则 构建查询命令时进行参数绑定,支持名称化参数。
    • 使用 ${...} 进行 SQL 文本替换 时虽然不会参与 PreparedStatement 但也算所传参的一种。

参数类型最终会经过 TypeHandler 处理,确保 JDBC 类型与 Java 类型的正确映射。