最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Java JdbcTemplate 实战手册:基于 Spring 轻量实现数据库增删改查
时间:2026-06-02 13:15:01 编辑:袖梨 来源:一聚教程网
Spring框架中的JdbcTemplate为开发者提供了简洁高效的数据库操作方式,通过封装JDBC模板代码,让开发者能更专注于业务逻辑实现。本文将详细介绍其核心功能与最佳实践。
简介
JdbcTemplate 作为 Spring JDBC 模块的核心工具类,有效解决了原生JDBC开发中的重复劳动问题。

原生 JDBC 需要开发者手动处理以下流程:
获取连接
创建 Statement
绑定 SQL 参数
遍历 ResultSet
关闭连接和结果集
处理 SQLException
而 JdbcTemplate 通过封装这些固定流程,让开发者只需关注三个核心要素:
执行什么 SQL
传什么参数
结果怎么映射
其核心价值在于:
JdbcTemplate 是 Spring 提供的轻量级数据库操作工具,适合直接写 SQL,又不想写一堆 JDBC 模板代码的场景。
原生 JDBC 写法
传统JDBC查询示例:
String sql = "select id, username, email, age from users where id = ?";Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;try {
connection = dataSource.getConnection();
statement = connection.prepareStatement(sql);
statement.setLong(1, 1L);
resultSet = statement.executeQuery(); if (resultSet.next()) {
User user = new User();
user.setId(resultSet.getLong("id"));
user.setUsername(resultSet.getString("username"));
user.setEmail(resultSet.getString("email"));
user.setAge(resultSet.getInt("age"));
return user;
} return null;
} finally {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}
其中仅有三处是业务相关:
- SQL语句内容
- 参数绑定方式
- 结果集到对象的映射
JdbcTemplate 写法
使用JdbcTemplate后的等效实现:
String sql = "select id, username, email, age from users where id = ?";User user = jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
User item = new User();
item.setId(rs.getLong("id"));
item.setUsername(rs.getString("username"));
item.setEmail(rs.getString("email"));
item.setAge(rs.getInt("age"));
return item;
}, 1L);
代码量显著减少,资源管理和异常处理都由框架自动完成。
JdbcTemplate 做了什么
架构定位示意图:
业务代码
|
v
JdbcTemplate
|
v
DataSource
|
v
数据库
关键特性说明:
- 不管理连接池,依赖注入的DataSource
- 在Spring Boot中自动配置
- 提供丰富的数据库操作方法
Maven 依赖
基础依赖配置:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency><dependency>
<groupId>com.mysqlgroupId>
<artifactId>mysql-connector-jartifactId>
<scope>runtimescope>
dependency>
开发测试可使用H2数据库:
<dependency>
<groupId>com.h2databasegroupId>
<artifactId>h2artifactId>
<scope>runtimescope>
dependency>
数据源配置
MySQL配置示例:
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
Spring Boot会自动创建DataSource和JdbcTemplate实例。
准备演示表
用户表结构及测试数据:
DROP TABLE IF EXISTS users;CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
age INT NOT NULL,
status VARCHAR(20) NOT NULL,
created_at DATETIME NOT NULL
);INSERT INTO users (username, email, age, status, created_at) VALUES
('张三', '[email protected]', 20, 'ACTIVE', '2026-01-01 10:00:00'),
('李四', '[email protected]', 25, 'ACTIVE', '2026-01-02 10:00:00'),
('王五', '[email protected]', 17, 'DISABLED', '2026-01-03 10:00:00');
实体类
import java.time.LocalDateTime;public class User {
private Long id;
private String username;
private String email;
private Integer age;
private String status;
private LocalDateTime createdAt; // 省略getter/setter方法
}
RowMapper:结果集映射
自定义映射处理器:
private static final RowMapper USER_ROW_MAPPER = (rs, rowNum) -> {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
user.setAge(rs.getInt("age"));
user.setStatus(rs.getString("status")); Timestamp createdAt = rs.getTimestamp("created_at");
if (createdAt != null) {
user.setCreatedAt(createdAt.toLocalDateTime());
} return user;
};
update:新增数据
插入操作示例:
public int save(User user) {
String sql = "insert into users values (?, ?, ?, ?, ?)";
return jdbcTemplate.update(
sql,
user.getUsername(),
user.getEmail(),
user.getAge(),
user.getStatus(),
user.getCreatedAt()
);
}
update:修改数据
public int updateEmail(Long id, String email) {
String sql = "update users set email = ? where id = ?";
return jdbcTemplate.update(sql, email, id);
}
update:删除数据
public int deleteById(Long id) {
String sql = "delete from users where id = ?";
return jdbcTemplate.update(sql, id);
}
queryForObject:查询单个值
统计查询示例:
public long countAll() {
String sql = "select count(*) from users";
Long count = jdbcTemplate.queryForObject(sql, Long.class);
return count == null ? 0L : count;
}
queryForObject:查询单个对象
public User findById(Long id) {
String sql = "select * from users where id = ?";
return jdbcTemplate.queryForObject(sql, USER_ROW_MAPPER, id);
}
注意:该方法要求查询结果必须存在且唯一。
查询可能不存在的数据
安全查询方案:
public Optional findOptionalById(Long id) {
String sql = "select * from users where id = ?";
List users = jdbcTemplate.query(sql, USER_ROW_MAPPER, id);
return users.isEmpty() ? Optional.empty() : Optional.of(users.get(0));
}
query:查询列表
分页查询实现:
public List findPage(int page, int size) {
int offset = (page - 1) * size;
String sql = "select * from users order by id desc limit ? offset ?";
return jdbcTemplate.query(sql, USER_ROW_MAPPER, size, offset);
}
BeanPropertyRowMapper:自动映射
简化映射方案:
public List findAllByBeanMapper() {
String sql = "select * from users";
return jdbcTemplate.query(
sql,
new BeanPropertyRowMapper<>(User.class)
);
}
返回自增主键
获取生成的主键值:
public Long saveAndReturnId(User user) {
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// 参数绑定
return ps;
}, keyHolder);
return keyHolder.getKey().longValue();
}
batchUpdate:批量写入
批量操作实现:
public int[] batchSave(List users) {
String sql = "insert into users values (?, ?, ?, ?, ?)";
return jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) {
User user = users.get(i);
// 参数绑定
}
@Override
public int getBatchSize() {
return users.size();
}
});
}
NamedParameterJdbcTemplate
命名参数用法:
String sql = "select * from users where status = :status and age >= :minAge";MapSqlParameterSource params = new MapSqlParameterSource()
.addValue("status", status)
.addValue("minAge", minAge);return namedJdbcTemplate.query(sql, params, USER_ROW_MAPPER);
事务控制
服务层事务管理:
@Transactional
public Long register(User user) {
Long userId = userRepository.saveAndReturnId(user);
userRepository.insertRegisterLog(userId, "注册成功");
return userId;
}
参数绑定和 SQL 注入
安全参数绑定原则:
使用参数绑定处理变量值
对动态表名/字段名进行白名单校验
异常处理
常见异常类型:
| 异常类型 | 触发场景 |
|---|---|
EmptyResultDataAccessException | 查询结果为空 |
DuplicateKeyException | 违反唯一约束 |
DataIntegrityViolationException | 数据完整性违规 |
JdbcTemplate 和 MyBatis 的区别
| 对比维度 | JdbcTemplate | MyBatis |
|---|---|---|
| SQL管理 | Java代码内嵌 | XML/注解分离 |
| 映射能力 | 基础映射 | 复杂映射支持 |
| 动态SQL | 手动处理 | 内置支持 |
常见使用建议
- SQL集中管理在Repository层
- 复杂映射优先使用RowMapper
- 查询可能为空时返回Optional
- 大批量操作注意分批次处理
常用方法汇总
| 方法 | 用途 |
|---|---|
update() | 执行DML操作 |
queryForObject() | 查询单条记录 |
query() | 查询多条记录 |
batchUpdate() | 批量操作 |
JdbcTemplate作为Spring生态中的轻量级数据访问方案,既保留了SQL的直观性,又大幅简化了JDBC模板代码。通过合理使用其提供的各种功能,可以高效完成大多数数据库操作需求,特别适合中小型项目或需要精细控制SQL的场景。
相关文章
- 我的世界如何切换视角按键 06-02
- 放置江湖落英谷树林路线指南:落英谷树林走法详解 06-02
- 阿里巴巴发布Ovis2.6-80B-A3B视觉语言模型,80B参数仅3B激活 06-02
- 2026英雄联盟暴走萝莉:最强出装攻略实战解析 06-02
- 我的世界如何显示坐标的指令是什么 06-02
- 字节跳动FaceCLIP模型实现文本驱动的面部主题个性化生成 06-02