JdbcTemplate
约 663 字大约 2 分钟
布欧-Lewyon
2026-05-15
首页 › Spring Boot › 数据访问 › JdbcTemplate
JdbcTemplate 是 Spring 对 JDBC 的轻量封装——消除了原生 JDBC 中的资源创建、释放、异常转换等样板代码,同时保留了 SQL 的完全控制力。
自动配置
引入 spring-boot-starter-jdbc(或 JPA starter)并配置数据源后,Spring Boot 自动装配 JdbcTemplate:
@Service
public class UserDao {
private final JdbcTemplate jdbcTemplate;
public UserDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}基本 CRUD
public class UserDao {
private final JdbcTemplate jdbcTemplate;
// 查询单行 → 对象
public User findById(Long id) {
return jdbcTemplate.queryForObject(
"SELECT id, username, age FROM users WHERE id = ?",
new BeanPropertyRowMapper<>(User.class),
id);
}
// 查询多行 → 列表
public List<User> findAll() {
return jdbcTemplate.query(
"SELECT id, username, age FROM users ORDER BY id",
new BeanPropertyRowMapper<>(User.class));
}
// 插入,返回自增主键
public long insert(User user) {
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO users(username, age) VALUES (?, ?)",
Statement.RETURN_GENERATED_KEYS);
ps.setString(1, user.getUsername());
ps.setInt(2, user.getAge());
return ps;
}, keyHolder);
return keyHolder.getKey().longValue();
}
// 更新
public int update(User user) {
return jdbcTemplate.update(
"UPDATE users SET username = ?, age = ? WHERE id = ?",
user.getUsername(), user.getAge(), user.getId());
}
// 删除
public int deleteById(Long id) {
return jdbcTemplate.update(
"DELETE FROM users WHERE id = ?", id);
}
}NamedParameterJdbcTemplate
当参数较多时,用命名参数代替 ? 占位符可读性更好:
public User findByUsernameAndAge(String username, int age) {
MapSqlParameterSource params = new MapSqlParameterSource()
.addValue("name", username)
.addValue("age", age);
return namedParameterJdbcTemplate.queryForObject(
"SELECT * FROM users WHERE username = :name AND age = :age",
params,
new BeanPropertyRowMapper<>(User.class));
}需要额外注入:
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public UserDao(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}RowMapper
BeanPropertyRowMapper 按字段名匹配列名和属性名。对于自定义映射,可以自己实现 RowMapper:
public class UserRowMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setAge(rs.getInt("age"));
return user;
}
}生产意识:
BeanPropertyRowMapper在列名和属性名不一致时不会报错,只会跳过匹配——这类 bug 很难在测试中发现(恰好测试数据有值)。建议在 RowMapper 中显式映射关键列,或使用Column注解配合BeanPropertyRowMapper的isCaseInsensitive=false开启严格匹配。对于大数据量查询(单表上万行),JdbcTemplate的query(String, RowMapper)是一次性加载全部结果到内存,可能触发 OOM。考虑使用queryForStream或分页查询分批处理。
小结
JdbcTemplate消除 JDBC 样板代码,保留 SQL 控制力。- 注入方式:构造器注入
JdbcTemplate或NamedParameterJdbcTemplate。 BeanPropertyRowMapper按列名自动映射;复杂场景实现RowMapper。KeyHolder获取自增主键。- 易错:
queryForObject查询不到记录时抛出EmptyResultDataAccessException,应用层需捕获或兜底。BeanPropertyRowMapper要求列名与属性名驼峰映射兼容(如user_name对应userName),如果列名是username则自动匹配username属性。 - 思考任务:实现一个完整的 UserDao,支持分页查询(使用
LIMIT ? OFFSET ?),用NamedParameterJdbcTemplate编写参数化查询。
上一节:数据源配置
下一节:Spring Data JPA
