JdbcTemplate 入门
1. 一句话简介
JdbcTemplate 是 Spring 对传统 JDBC 的最薄一层封装,位于 spring-boot-starter-jdbc 之中。它解决了原生 JDBC 反复写"获取连接、拼 SQL、创建 Statement/ResultSet、逐行取字段、关闭资源、转换异常"的样板代码问题,把连接获取、异常转换、资源释放都交给框架统一处理,开发者只需专注于写 SQL。
本模块 demo-orm-jdbctemplate 展示了它的核心能力:通过 jdbcTemplate.update(...) 执行增删改(返回影响行数),通过 jdbcTemplate.queryForObject(sql, args, new BeanPropertyRowMapper<>(clazz)) 查询单条、jdbcTemplate.query(...) 查询列表,并用 BeanPropertyRowMapper 自动把下划线列名(如 phone_number)映射成驼峰属性(phoneNumber)。模块还基于自定义注解(@Table、@Column、@Pk、@Ignore)+ 反射手写了一个通用 BaseDao,动态拼接 SQL 实现通用 CRUD——这正是 MyBatis-Plus、JPA 这类 ORM 框架的底层原理,用最小的代码量看清"从 SQL 到对象"的完整链路。
核心 API 很简单:update() 管增删改、queryForObject() 管查单条、query()/queryForList() 管查列表,配合参数占位符 ? 天然避免 SQL 注入。
2. 什么时候使用
全流程使用约定:新增实体只须继承 BaseDao<T, P> 并加几个注解即可复用 CRUD,如 UserDao extends BaseDao<User, Long> 仅写了 5 个委托方法就获得了 5 个通用能力,业务类(Dao)几乎不再手写 SQL(本模块用 Hutool 拼 SQL 是为了演示原理,实际常用写法恰是手写的 SQL 字符串)。
- ✅ 适用场景
- 简单/标准 CRUD 的小型项目:表结构简单、查询不复杂,不需要引入重型 ORM,用 JdbcTemplate 够用且零额外心智负担。
- 追求极致 SQL 可控性和透明度的团队:SQL 全部手写在代码里或与逻辑紧邻,没有框架的"隐式"行为(无懒加载、无脏检查、无一层层代理),出问题可以直接拿到执行的 SQL 排查,本模块也通过 debug 日志打印了实际 SQL 和参数。
- 对性能敏感、想绕开 ORM 开销的场景:JdbcTemplate 直连 SQL + 连接池复用连接,没有 ORM 的会话缓存、对象图构建、反射开销,能拿到 JDBC 层面的原始性能。
- 学习 Spring/JDBC/ORM 底层原理:用它理解事务、
RowMapper、连接池如何工作,再去看 JPA/MyBatis 会容易很多,且它能直接嵌入任何用 Spring 的既有系统。 - 与存储过程、复杂原生 SQL、多表 join、批量写配合:手写 SQL 最自由,动态拼接条件时只需自己用占位符
?传参即可,本模块的findByExample正是用非 null 字段动态拼WHERE ... = ?的高手写法。
- ❌ 不适用/需谨慎
- 复杂领域模型、有大量关联(一对多/多对多)映射:JdbcTemplate 不提供关系映射,需手写 join 并手动在 Service 层组装对象图;JPA/MyBatis 在这方面更省力。
- 动态 SQL 多、查询条件随意组合的系统:如后台管理列表的多条件筛选、统计报表。手拼
WHERE 1=1和?很繁琐且易错,MyBatis 的<if>动态 SQL 更合适。 - 希望大幅减少代码量的团队:JdbcTemplate 的 SQL、结果映射、分页都要自己写。MyBatis-Plus/JPA 的方法名派生查询(如
findByName)可省去大量样板。本模块虽用BaseDao简化了增删改,但复杂查询仍需手写。 - 对 SQL 注入不够警惕的团队:JdbcTemplate 本身安全(占位符),但手拼 SQL 时若忘了用
?而直接拼接字符串,风险和被写的动态 SQL 一样高,需要编码纪律约束。 - 需要跨数据库兼容/方言隔离的大型系统:JdbcTemplate 的 SQL 是手写的,换库时需手动改 SQL;JPA 通过方言(Dialect)自动适配,分页等特性更省心。
3. 常见业务场景
- 标准 RESTful 用户/资源管理:对单张表做增删改查,如"创建用户、按 ID 查用户、更新邮箱和手机号、删除用户、按条件查列表"。本模块
UserController用@PostMapping/@PutMapping/@DeleteMapping/@GetMapping一一对应这 5 个操动作,SQL 只有INSERT/DELETE/UPDATE/SELECT,JdbcTemplate 的update/query恰好全覆盖,是最典型的落地场景。 - 按对象属性做条件查询(Example 查询):查询条件不固定,"有值就过滤、无值则忽略",如
?status=1查启用用户、或空条件查全部。本模块BaseDao.findByExample通过ignoreNull过滤掉 null 字段、动态拼出的WHERE 1=1 and status = ?正是这类场景的模板,直接把一个 User 对象当查询条件容器,代码极简。 - 账号体系与密码加盐处理:在写入前在 Service 层做业务加工再落库。本模块
UserServiceImpl.save先用IdUtil.simpleUUID()生成随机盐、用SecureUtil.md5(前缀 + 明文 + salt)加密,再把密文和盐写库。JdbcTemplate 不越权做任何数据加工,把"加密这种 SQL 管不到的活"干净地留给 Service 层,职责边界清晰。 - 批量初始化与脚本持久化:在
application.yml里配initialization-mode: always+classpath:db/schema.sql、data.sql,应用启动时自动建表、灌测试数据,配合 HikariCP 连接池参数(maximum-pool-size、connection-test-query: SELECT 1 FROM DUAL等)。这适合演示、测试环境,JdbcTemplate + Spring 自动配置让"配数据源 + 跑脚本"几乎零代码。 - 日志与可观测性增强的调试场景:把执行的 SQL 和参数以 debug 级别打出来(本模块
log.debug("【执行SQL】SQL:{}", sql)),在线下联调、排查慢查询/误删时非常见价值。JdbcTemplate 简单的"一行 SQL 抵一个方法"让这类定位成本远低于 ORM 的隐式操作。
4. 同类技术对比
| 维度 | JdbcTemplate | Spring Data JPA (Hibernate) | MyBatis / MyBatis-Plus | MyBatis-Plus 单独看 |
|---|---|---|---|---|
| 抽象层级 | 最低,直接手写 SQL | 最高,注解/方法名派生驱动、近乎零 SQL | 中等,XML/注解映射自定义 SQL | 高,内置通用 CRUD、ActiveRecord 风格 |
| 学习成本 | 低,会 SQL + JDBC 即可 | 中,需懂 JPA 规范与 Hibernate 缓存/懒加载 | 中,需懂 Mapper 映射与动态 SQL | 低(对已会 MyBatis 者),对新手中等 |
| SQL 可控性/灵活性 | 极高,全部手写 | 低,复杂查询需 @Query 或原生 SQL |
高,动态 SQL 是一等公民 | 高,通用 CRUD + 逻辑删除/乐观锁内置 |
| 代码量 | 多,SQL 与映射均自理 | 少,继承 Repository 即可 | 中等,需写 Mapper 接口与 XML | 少,继承 IService 即得全套 CRUD |
| 复杂关联/多表映射 | 弱,需手写 join 与组装 | 强,@OneToMany/@ManyToMany 自动级联 |
中,可手写 resultMap | 中,需配注解或 XML |
| 性能(常规读写) | 高,直连 SQL 无缓存开销 | 中低,一级缓存/懒加载收益仅在特定场景 | 中,映射开销小 | 同 MyBatis |
| 通用 CRUD 内置能力 | 无,靠自封基类(如本模块 BaseDao) |
有,Repository 方法名派生 | 无,需自己写 XML | 有,IService + Wrapper 条件构造器 |
| 动态 SQL 支持 | 弱,手拼 ? 与 WHERE 1=1 |
弱,靠 @Query/Specification |
强,<where>/<if>/<foreach> |
强,LambdaQueryWrapper |
| 分页 | 手写 LIMIT |
自带 Pageable |
需插件 | 内置分页插件 |
| 事务/连接池集成 | Spring 自动 | Spring Data 自动 | Spring 自动 | Spring 自动 |
| 适用规模 / 定位 | 小型项目、性能敏感、讲透明度 | 领域模型驱动、复杂对象模型、跨库 | CRUD + 复杂查询并存的企业系统 | 标准化 CRUD + 快速开发 |
选型建议
- 想要 SQL 绝对可控、追求性能、或项目简单只想少引入概念 → 选 JdbcTemplate。它在"一次 SQL 一念之间"的场景(单表 CRUD、存储过程、批量写、与老系统混用)效率最高,也是入门 JDBC 的最优起点。
- 领域模型复杂、对象间关联多、强调"以对象为中心"的建模与敏捷迭代 → 选 Spring Data JPA。一组一组的
@OneToMany、方法名派生查询能显著减少代码,但代价是更高的抽象层与更深的隐式行为,适合用它换取研发效率的团队。 - 业务以复杂查询、动态 SQL、多条件筛选、报表为主,且需要精细控制 SQL → 选 MyBatis 或 MyBatis-Plus。企业级后台系统最常落在这条路线,MyBatis-Plus 还额外白送了逻辑删除、乐观锁、分页、代码生成器等加班神器。
- 综合建议:团队能力与业务形态决定选型——小型/研究型/性能敏感项目用 JdbcTemplate,复杂对象域用 JPA,企业 CRUD + 复杂查询用 MyBatis-Plus。把几个都跑通(本仓库有对应的
demo-orm-mybatis、demo-orm-jpa、demo-orm-mybatis-plus模块)再定,是最稳的做法。