背景

上两篇文章<模板方法模式与JdbcTemplate>和<新手坑揭秘:JdbcTemplate的queryForList>用的示例都是没有参数的,在有参数的时候JdbcTemplate该如何使用呢?

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql

JdbcTemplate支持带参数的sql执行,内部使用SimplePreparedStatementCreator封装了PreparedStatement,使用newArgPreparedStatementSetter来封装参数。

另外JdbcTemplate通过Object[]数组来给PreparedStatement来设置参数,这容易造成混乱,NamedParameterJdbcTemplate支持通过名称的方式来传递参数给PreparedStatement。

 

JdbcTemplate实例和NamedParameterJdbcTemplate实例

前期准备

表创建

CREATE TABLE `student1` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`first_name` varchar(100) DEFAULT NULL,

`last_name` varchar(100) DEFAULT NULL,

`age` int(11) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

插入数据

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_02

在spring-jdbc项目中增加mysql的依赖:

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_03

JdbcTemplate实例

定义JavaBean

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_04

定义映射对象

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_05

配置DataSource和JdbcTemplate

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_06

测试程序

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_07

运行程序结果:

5,www,baidu.com,23

7,www,baidu.com,23

8,www,baidu.com,23

从上面的测试程序看到,

1.传入的参数是以Object[]数组形式传入的,如果参数比较多,容易搞混乱

2.在java中我们更习惯使用参数名称来做这件事,spring做了一些工作:NamedParameterJdbcTemplate

NamedParameterJdbcTemplate实例

测试程序

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_08

运行结果

5,www,baidu.com,23

7,www,baidu.com,23

8,www,baidu.com,23

  深入原理

JdbcTemplate

关键点:query()方法

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_09

第一步:将参数Object[]数组封装成ArgumentPreparedStatementSetter

@Override

@Nullable

public <T> T query(String sql, @Nullable Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {

return query(sql, newArgPreparedStatementSetter(args), rse);

}

query()方法调用ArgumentPreparedStatementSetter的方法setValues()设置参数

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_10

第二步:封装sql到PrepareStatement到SimplePreparedStatementCreator中,其执行方法为:

createPreparedStatement在JdbcTemplate.java#execute方法中调用

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_11

第三步:使用RowMapper实现类将ResultSet结果转换成javaBean

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_12

NamedParameterJdbcTemplate

第一步将Map参数封装为MapSqlParameterSource

第二步将sql和参数封装到PreparedStatementCreator

第三步:调用JdbcTemplate的query()方法

带参数sql执行比较:JdbcTemplate vs NamedParameterJdbcTemplate_参数sql_13

  总结

从JdbcTemplate和NamedParameterJdbcTemplate来看,针对jdbc要用的三个要素:sql,参数param,ResultSet结果转换分别进行了封装。

  • sql可以封装成SimplePreparedStatementCreator或者PreparedStatementCreator的实现类

  • 参数param可以封装成ArgumentPreparedStatementSetter或者PreparedStatementCreator实现类

  • ResultSet结果转换可以封装成RowMapper实现类或者RowCallbackHandler实现类