JdbcTemplate封装了连接管理、异常转译、资源释放和SQL注入防护,避免手写JDBC时因遗漏close()导致连接泄漏或SQLException难定位;它依赖DataSource自动复用连接,要求通过@Autowired注入而非new,参数须用?占位符,查询单行用queryForObject()、多行用query()、增删改用update()并检查返回值,批量操作用batchUpdate(),空结果不抛异常但queryForObject()在无结果或多结果时会抛特定异常,事务需配合@Transactional注解实现。

为什么直接用 JdbcTemplate 而不手写 Connection/PreparedStatement
因为重复处理连接获取、异常转译、资源关闭太容易出错。比如忘了 close() 会导致连接泄漏,SQLException 直接抛出又难定位业务含义。JdbcTemplate 把这些封装掉了——它不管理连接池,但会安全地复用你给的 DataSource,自动处理 ResultSet 映射、事务边界和 SQL 注入防护(通过占位符参数)。
常见错误现象:java.lang.NullPointerException 在调用 query() 前没注入 JdbcTemplate 实例;或手动拼接 SQL 字符串导致 SQL 注入(如 "WHERE name = '" + name + "'")。
- 必须通过构造器或
@Autowired注入已配置好DataSource的JdbcTemplate,不能 new 出来就用 - 所有参数一律走
?占位符,用 Object 数组或Map传值,别字符串拼接 - 查询单行用
queryForObject(),多行用query(),无结果用update()
update() 执行 INSERT/UPDATE/DELETE 时要注意什么
update() 是增删改的统一入口,返回影响行数(int),可用于判断是否成功(比如插入后检查是否为 1)。它底层调用 PreparedStatement.executeUpdate(),所以天然防注入。
典型误用:用 update() 执行 SELECT 语句(会报 Invalid SQL statement);或忽略返回值,在主键自增场景下没拿到生成的 ID。
- 插入后需主键:改用
update(String sql, PreparedStatementSetter pss)配合KeyHolder,例如new GeneratedKeyHolder() - 批量操作优先用
batchUpdate(),避免循环调用update()导致 N+1 次网络往返 - SQL 中字段名别写错大小写——MySQL 默认不区分,但 PostgreSQL 和 Oracle 严格区分,容易查不到列
用 query() 查多行数据时怎么避免 DataAccessException
query() 要求传一个 RowMapper 或 RowMapper 实现,把每行 ResultSet 映射成 Java 对象。如果映射逻辑写错(比如字段名拼错、类型不匹配),就会在运行时报 IncorrectResultSetColumnCountException 或 CannotConvertValueException。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
常见坑:直接用 BeanPropertyRowMapper 但实体类字段名和数据库列名不一致(如数据库是 user_name,Java 是 userName),导致字段为 null。
- 优先手写匿名
RowMapper,明确指定rs.getString("user_name")→user.setName(...),比靠反射更可控 - 若用
BeanPropertyRowMapper,加构造参数new BeanPropertyRowMapper(User.class)并确保列别名与字段名一致(SQL 写SELECT user_name AS userName) - 空结果集不会抛异常,返回空
List,所以判空别用!= null,要用.isEmpty()
为什么 queryForObject() 经常抛 EmptyResultDataAccessException
这个方法假定“一定有且仅有一条结果”,查不到就抛 EmptyResultDataAccessException,查到多条抛 IncorrectResultSizeDataAccessException。它适合主键查询、聚合函数(COUNT(*))等确定性场景。
典型错误:拿它查模糊条件(如 LIKE '%abc%'),结果可能 0 条或 N 条,必然崩。
- 不确定是否存在时,改用
query()+ 取List第一个元素,并判空 - 只关心数量:用
queryForObject("SELECT COUNT(*) FROM ...", Integer.class),类型必须匹配(Long.class也行,但别用int.class) - 想兼容空值又不想捕获异常?Spring 5.3+ 提供
queryOptional(),返回Optional,但注意它只支持单列查询(如String、Integer),不支持对象映射
最易被忽略的一点:事务控制不在 JdbcTemplate 里。它只是执行工具,@Transactional 得加在 service 方法上,否则 update 成功但异常回滚不了。还有,DataSource 必须配对——HikariCP 或 Druid 连接池的配置项(如 maximumPoolSize)直接影响并发性能,别全用默认值硬扛。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










