摘要:工作这么多年了,第一次使用 JdbcTemplate 。使用的时候当然要全方位的了解它。了解它的使用方式,使用场景以及注意事项等相关知识,今天就和大家一起学习一下吧
工作这么多年了,第一次使用 JdbcTemplate 。使用的时候当然要全方位的了解它。了解它的使用方式,使用场景以及注意事项等相关知识,今天就和大家一起学习一下吧
JdbcTemplate 是 Spring 框架核心包的一部分,位于 spring-jdbc 模块中,因此通常不用我们再额外引入依赖,直接就可以。它封装了 JDBC 的核心流程,消除了传统的 JDBC 开发中大量重复的代码。当然最核心的就是直接在代码中执行 SQL #技术分享 :
jdbcTemplate.update("INSERT INTO users(name, email) VALUES(?, ?)", "张三", "zhangsan@example.com");User user = jdbcTemplate.queryForObject( "SELECT * FROM users WHERE id = ?", new Object{1}, new BeanPropertyRowMapper(User.class));因此它和 mybatis 这些 orm 框架相比使用就更加的简单了,效率也更高。但是在开发中我们不会去用它来写业务代码,毕竟规范通常来说更加的重要。
它的使用场景在哪些地方呢,以本次工作场景为例。这次的业务需求 需要实现动态建表的功能,以及在插入数据的时候,表名 和 字段都是动态的。利用 orm 框架去处理 ddl 语句显示不是很好,以及表名和字段都是需要计算才知道显然在 java 代码中拼接好 SQL 之后直接执行更好。
所以在执行 ddl 语句,存储过程,以及 SQL 必须在程序中进行拼接的场景,用 JdbcTemplate 更为合适
在实际项目中,JdbcTemplate常与JPA或MyBatis等ORM框架混合使用。ORM框架处理常规业务逻辑,而JdbcTemplate处理特殊场景如ddl、复杂查询、批量操作等。这种混合模式能兼顾开发效率和执行性能。(并且在springboot工程中通常不需要在单独引入依赖,直接使用就可以了)
在 Spring Boot 中,只需在 application.properties 中配置数据源,Spring 会自动创建 JdbcTemplate bean:
spring.datasource.url=jdbc:mysql://localhost:3306/testspring.datasource.username=usernamespring.datasource.password=passwordspring.datasource.driver-class-name=com.mysql.jdbc.Driver导入 bean 就可以直接使用了
@Resourceprivate JdbcTemplate jdbcTemplate;JdbcTemplate 提供了多种查询方法,以下是一些常用示例:
查询单个值:
int count = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM users", Integer.class);查询单条记录:
User user = jdbcTemplate.queryForObject( "SELECT * FROM users WHERE id = ?", new Object{1}, new BeanPropertyRowMapper(User.class));查询多条记录:
List users = jdbcTemplate.query( "SELECT * FROM users", new BeanPropertyRowMapper(User.class));插入数据:
jdbcTemplate.update( "INSERT INTO users(name, email) VALUES(?, ?)", "张三", "zhangsan@example.com");更新数据:
int rowsAffected = jdbcTemplate.update( "UPDATE users SET email = ? WHERE id = ?", "newemail@example.com", 1);删除数据:
int rowsDeleted = jdbcTemplate.update( "DELETE FROM users WHERE id = ?", 1);JdbcTemplate 支持高效的批量操作:
jdbcTemplate.batchUpdate( "INSERT INTO users(name, email) VALUES(?, ?)", new BatchPreparedStatementSetter { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setString(1, "User" + i); ps.setString(2, "user" + i + "@example.com"); } @Override public int getBatchSize { return 10; } });使用 NamedParameterJdbcTemplate 可以更清晰地处理参数:
NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(dataSource);Map params = new HashMap; params.put("id", 1); params.put("email", "newemail@example.com");namedTemplate.update( "UPDATE users SET email = :email WHERE id = :id", params);直接把原生的 SQL 语句执行就行了,比如建表操作:
public void createUserTable { jdbcTemplate.execute("CREATE TABLE users (" + "id BIGINT PRIMARY KEY AUTO_INCREMENT," + "username VARCHAR(50) NOT NULL UNIQUE," + "password VARCHAR(100) NOT NULL," + "email VARCHAR(100)," + "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP," + "updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +}注意事项实际使用中仍有一些需要注意的关键点,遵循这些最佳实践可以避免常见问题并提高代码质量和性能。关键注意事项包括:
始终防范SQL注入合理管理资源和内存使用正确处理和记录异常适当使用事务管理优化批量操作性能提高SQL可维护性String sql = "SELECT *jdbcTemplate.query(sql, rowMapper);jdbcTemplate.query("SELECT * FROM users WHERE name = ?", new Object{name}, rowMapper);jdbcTemplate.query("SELECT * FROM large_table", rs -> { while (rs.next) { processRow(rs); } });问题 :JdbcTemplate 会将 SQLException 转换为 DataAccessException
正确处理 :
捕获特定的DataAccessException子类而非泛化的异常记录完整的异常信息以便排查问题try { jdbcTemplate.update("UPDATE accounts SET balance = ? WHERE id = ?", amount, accountId);} catch (DuplicateKeyException e) { log.error("Duplicate key violation", e); throw new BusinessException("Account already exists");} catch (DataAccessException e) { log.error("Database access error", e); throw new ServiceException("Database operation failed");}注意:DDL语句通常是自动提交的,不受常规事务管理控制
最佳实践 :
对需要原子性的一组操作使用 @Transactional 注解注意事务传播行为和隔离级别设置@Transactionalpublic void transferMoney(Long fromId, Long toId, BigDecimal amount) { jdbcTemplate.update("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, fromId); jdbcTemplate.update("UPDATE accounts SET balance = balance +}注意事项 :
批量操作使用 batchUpdate 而非循环执行单条更新重用预编译语句(JdbcTemplate内部已优化)考虑使用 NamedParameterJdbcTemplate 提高复杂SQL可读性jdbcTemplate.batchUpdate( "INSERT INTO users (name, email) VALUES (?, ?)", new BatchPreparedStatementSetter { public void setValues(PreparedStatement ps, int i) throws SQLException { User user = users.get(i); ps.setString(1, user.getName); ps.setString(2, user.getEmail); } public int getBatchSize { return users.size; } });将SQL语句提取到常量或配置文件中使用Spring的 @Sql 注解管理测试数据考虑使用SQL构建工具如QueryDSLprivate static final String FIND_USER_BY_ID = "SELECT id, name, email FROM users WHERE id = ?";public User findById(Long id) { return jdbcTemplate.queryForObject( FIND_USER_BY_ID, new Object{id}, new BeanPropertyRowMapper(User.class)); }JdbcTemplate 在工作中还是很少用到的,业务代码还是用 orm 。特殊的场景比如执行 ddl 、存储过程,或者 orm 不方便操作的可以考虑使用 jdbcTemplate 执行这部分语句 。当然在使用过程的注意事项还是要了解的,比如防止 SQL 注入等问题。
来源:墨码行者