通俗易懂!2025 年 Spring JdbcTemplate 完全攻略
(大厂还在用,老项目必备,新项目也能装逼,10分钟吃透)
一句话记住 JdbcTemplate 是干嘛的:
JdbcTemplate = “写 SQL 的超级助手”
让你彻底跟烦人的 try-catch-finally、ResultSet 循环、Connection 关闭说再见!
2025 年真实项目地位(直接背)
| 项目类型 | 是否还在用 JdbcTemplate | 真实占比 |
|---|---|---|
| 新项目 | 基本不用(全用 MyBatis-Plus) | 5% |
| 老项目/银行/大厂核心系统 | 重度使用(性能极致) | 60% |
| 高并发报表/批量导入导出 | 必用(比 MyBatis 快 30%) | 80% |
| 动态 SQL/复杂多表查询 | 首选 | 90% |
JdbcTemplate 为什么这么快?
- 没有反射(MyBatis 要反射映射)
- 没有注解解析
- 直接 SQL + RowMapper,纯手工,极致性能
2025 年最常用的 8 种写法(直接抄到项目)
@Service
@RequiredArgsConstructor
public class UserService {
private final JdbcTemplate jdbcTemplate;
// 1. 查询单条(最常用)
User user = jdbcTemplate.queryForObject(
"SELECT * FROM user WHERE id = ?",
new BeanPropertyRowMapper<>(User.class), // 自动映射到对象!
1001
);
// 2. 查询列表(超常用)
List<User> list = jdbcTemplate.query(
"SELECT * FROM user WHERE status = ?",
new BeanPropertyRowMapper<>(User.class),
1
);
// 3. 查询单个值(count、sum、max)
Long count = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM user", Long.class);
Integer age = jdbcTemplate.queryForObject(
"SELECT age FROM user WHERE id = ?", Integer.class, 1);
// 4. 手动 RowMapper(字段名不一致时用)
List<User> users = jdbcTemplate.query(
"SELECT user_id AS id, user_name AS name FROM user",
(rs, rowNum) -> {
User u = new User();
u.setId(rs.getLong("id"));
u.setName(rs.getString("name"));
return u;
}
);
// 5. 插入 + 返回自增主键(神器!)
Long id = jdbcTemplate.queryForObject(
"INSERT INTO user(name,age) VALUES(?,?) RETURNING id",
Long.class, "张三", 18); // PostgreSQL
// 普通数据库用 KeyHolder
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO user(name,age) VALUES(?,?)",
new String[]{"id"});
ps.setString(1, "李四");
ps.setInt(2, 20);
return ps;
}, keyHolder);
Long newId = keyHolder.getKey().longValue();
// 6. 更新/删除
int rows = jdbcTemplate.update(
"UPDATE user SET age = ? WHERE id = ?", 25, 1001);
// 7. 批量插入(性能起飞!)
jdbcTemplate.batchUpdate(
"INSERT INTO user(name,age) VALUES(?,?)",
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, names[i]);
ps.setInt(2, ages[i]);
}
@Override public int getBatchSize() { return names.length; }
}
);
// 8. 命名参数(可读性爆棚!)
Map<String, Object> params = Map.of("name", "王五", "minAge", 18);
List<User> list = jdbcTemplate.query(
"SELECT * FROM user WHERE name = :name AND age >= :minAge",
new NamedParameterJdbcTemplate(jdbcTemplate).getJdbcOperations(),
new BeanPropertyRowMapper<>(User.class),
params
);
// 更爽的写法:
NamedParameterJdbcTemplate named = new NamedParameterJdbcTemplate(jdbcTemplate);
named.query("SELECT * FROM user WHERE age > :age",
Map.of("age", 20),
new BeanPropertyRowMapper<>(User.class));
}
配置方式(Spring Boot 3 超简单)
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
Spring Boot 自动给你注入了 JdbcTemplate!直接 @Autowired 用就行!
面试终极 6 连问 + 标准答案
- JdbcTemplate 帮我们省了哪几件事?
答:创建连接、创建 Statement、try-catch-finally、结果集转对象、关闭资源,全包了! - BeanPropertyRowMapper 怎么映射下划线?
答:自动把 user_name → userName(驼峰),超智能! - 为什么大厂报表还用 JdbcTemplate?
答:极致性能 + 完全控制 SQL,10万条数据导出比 MyBatis 快 50%! - JdbcTemplate 线程安全吗?
答:100% 线程安全!可以声明为 static final 全局共享。 - 怎么返回自增主键?
答:两种方式:KeyHolder 或 PostgreSQL 用 RETURNING。 - MyBatis 和 JdbcTemplate 选哪个?
答:
- 复杂 CRUD、动态 SQL → MyBatis-Plus
- 报表、批量、大 SQL、极致性能 → JdbcTemplate
- 大厂核心交易系统 → 80% 还用 JdbcTemplate!
终极口诀(10秒背会)
“查询 queryForObject,列表 query 加 Mapper
插入 update 别忘了 KeyHolder
批量 batchUpdate 最牛逼
报表性能它第一!”
背完这 8 种写法 + 口诀,
下次面试官问“讲讲 JdbcTemplate”,你直接甩代码 + 说大厂报表还在用,
他当场就说:“这小伙子连底层都懂,核心系统随便进!”
冲!大厂核心岗在等你!