一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Java JdbcTemplate 实战手册:基于 Spring 轻量实现数据库增删改查

时间:2026-06-02 13:15:01 编辑:袖梨 来源:一聚教程网

Spring框架中的JdbcTemplate为开发者提供了简洁高效的数据库操作方式,通过封装JDBC模板代码,让开发者能更专注于业务逻辑实现。本文将详细介绍其核心功能与最佳实践。

简介

JdbcTemplate 作为 Spring JDBC 模块的核心工具类,有效解决了原生JDBC开发中的重复劳动问题。

Java JdbcTemplate 实战指南:用 Spring 轻量完成数据库增删改查

原生 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();
    }
}

其中仅有三处是业务相关:

  1. SQL语句内容
  2. 参数绑定方式
  3. 结果集到对象的映射

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
数据库

关键特性说明:

  1. 不管理连接池,依赖注入的DataSource
  2. 在Spring Boot中自动配置
  3. 提供丰富的数据库操作方法

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 的区别

对比维度JdbcTemplateMyBatis
SQL管理Java代码内嵌XML/注解分离
映射能力基础映射复杂映射支持
动态SQL手动处理内置支持

常见使用建议

  1. SQL集中管理在Repository层
  2. 复杂映射优先使用RowMapper
  3. 查询可能为空时返回Optional
  4. 大批量操作注意分批次处理

常用方法汇总

方法用途
update()执行DML操作
queryForObject()查询单条记录
query()查询多条记录
batchUpdate()批量操作

JdbcTemplate作为Spring生态中的轻量级数据访问方案,既保留了SQL的直观性,又大幅简化了JDBC模板代码。通过合理使用其提供的各种功能,可以高效完成大多数数据库操作需求,特别适合中小型项目或需要精细控制SQL的场景。

热门栏目