对spring JdbcTemplate 代码的一些理解
2016-03-18 00:23
465 查看
Spring将数据访问过程中固定和可变的部分明确的划分为两个不同的类:模板(template)和回调(callback)。模板管理过程中固定的部分,而回调处理自定义的数据访问代码。
Spring的JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码,让我们只需编写从数据库读写数据的必须代码。
对于JdbcTemplate类就从query相关的函数开始看吧。
对于query函数按参数大致可以分为三类:callback参数分别为 ResultSetExtractor<T>、RowCallbackHandler、RowMapper<T>
如:
等
对于ResultSetExtractor<T>类型的参数,不需要再进行封装,在将前两个参数封装成PreparedStatementCreator和PreparedStatementSetter后,就会调用excute函数进行执行。
从代码中可以看到,在excute函数的第二个参数中直接创建了PreparedStatementCallback的回调实例,里面首先进行结果查询,得到resultset结果集。然后调用传进来的ResultSetExtractor对结果集进行转换。
如果query的回调参数是RowCallbackHandler类型。如:
可以看到在实现的extractData函数中对resultset结果集进行逐行便利,调用RowCallbackHandler的processRow函数进行逐行处理结果。
所以RowCallbackHandler的作用是对结果集中的一行数据进行处理。每一次调用只处理一行数据。最终的结果RowCallbackHandlerResultSetExtractor不负责保存和返回,而是由RowCallbackHandler的实现类自己负责保存。因此query函数返回值为void。
第三种RowMapper<T>回调参数类型,如:
从代码中可以看到extractData函数调用RowMapper<T>的mapRow函数对结果集进行逐行处理,extractData负责对所有行的处理结果进行保存。RowMapper<T>的mapRow函数将返回每一行的数据处理为T类型的对象实例后返回。
这就是在使用RowMapper<T>和RowCallbackHandler上的区别。
下面再看下query函数的第一个参数,第一个参数基本上是两种类型,一个是String,一个是PreparedStatementCreator类型,都是用来表示对sql语句的封装。String类型的表示传进来的sql语句,大多数最终都会封装成PreparedStatementCreator接口类型,除了public <T> List<T> query(String sql, RowMapper<T> rowMapper)
public void query(String sql, RowCallbackHandler rch) throws DataAccessException
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException
在JdbcTemplate中定义了一个SimplePreparedStatementCreator内部类来实现PreparedStatementCreator接口。
/**
* Simple adapter for PreparedStatementCreator, allowing to use a plain SQL statement.
*/
private static class SimplePreparedStatementCreator implements PreparedStatementCreator, SqlProvider {
private final String sql;
public SimplePreparedStatementCreator(String sql) {
Assert.notNull(sql, "SQL must not be null");
this.sql = sql;
}
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
return con.prepareStatement(this.sql);
}
public String getSql() {
return this.sql;
}
}
这个类很简单,基本上是将要调用的sql与PreparedStatement进行了封装。
对于query函数的另一个参数,可以看作是sql语句的赋值参数。这个参数有两种类型,一个是Object[],另一个是PreparedStatementSetter接口类型的参数。Object[]数组类型的参数会封装成ArgumentPreparedStatementSetter类。从这个接口和的名字也可以看出该类的作用。就是用来设置PreparedStatement的,用来对PreparedStatement进行赋值操作的。
**
* Simple adapter for {@link PreparedStatementSetter} that applies a given array of arguments.
*
* @author Juergen Hoeller
* @since 3.2.3
*/
public class ArgumentPreparedStatementSetter implements PreparedStatementSetter, ParameterDisposer {
private final Object[] args;
/**
* Create a new ArgPreparedStatementSetter for the given arguments.
* @param args the arguments to set
*/
public ArgumentPreparedStatementSetter(Object[] args) {
this.args = args;
}
public void setValues(PreparedStatement ps) throws SQLException {
if (this.args != null) {
for (int i = 0; i < this.args.length; i++) {
Object arg = this.args[i];
doSetValue(ps, i + 1, arg);
}
}
}
/**
* Set the value for prepared statements specified parameter index using the passed in value.
* This method can be overridden by sub-classes if needed.
* @param ps the PreparedStatement
* @param parameterPosition index of the parameter position
* @param argValue the value to set
* @throws SQLException
*/
protected void doSetValue(PreparedStatement ps, int parameterPosition, Object argValue) throws SQLException {
if (argValue instanceof SqlParameterValue) {
SqlParameterValue paramValue = (SqlParameterValue) argValue;
StatementCreatorUtils.setParameterValue(ps, parameterPosition, paramValue, paramValue.getValue());
}
else {
StatementCreatorUtils.setParameterValue(ps, parameterPosition, SqlTypeValue.TYPE_UNKNOWN, argValue);
}
}
public void cleanupParameters() {
StatementCreatorUtils.cleanupParameters(this.args);
}
}
现在理解了这几种基本的调用后,对于JdbcTemplate中实现的queryForList、queryForMap、queryForObject等函数就好理解了。基本上就是上面三种基本形式的再封装以及相关接口的实例化实现。
Spring的JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码,让我们只需编写从数据库读写数据的必须代码。
对于JdbcTemplate类就从query相关的函数开始看吧。
对于query函数按参数大致可以分为三类:callback参数分别为 ResultSetExtractor<T>、RowCallbackHandler、RowMapper<T>
如:
public <T> T query( PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws DataAccessException public void query(PreparedStatementCreator psc, RowCallbackHandler rch) throws DataAccessException public <T> List<T> query(PreparedStatementCreator psc, RowMapper<T> rowMapper)
public <T> T query(String sql, Object[] args, int[] argTypes, ResultSetExtractor<T> rse) throws DataAccessException public void query(String sql, Object[] args, int[] argTypes, RowCallbackHandler rch) throws DataAccessException public <T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper) throws DataAccessException
等
对于ResultSetExtractor<T>类型的参数,不需要再进行封装,在将前两个参数封装成PreparedStatementCreator和PreparedStatementSetter后,就会调用excute函数进行执行。
public <T> T query( PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws DataAccessException { Assert.notNull(rse, "ResultSetExtractor must not be null"); logger.debug("Executing prepared SQL query"); return execute(psc, new PreparedStatementCallback<T>() { public T doInPreparedStatement(PreparedStatement ps) throws SQLException { ResultSet rs = null; try { if (pss != null) { pss.setValues(ps); } rs = ps.executeQuery(); ResultSet rsToUse = rs; if (nativeJdbcExtractor != null) { rsToUse = nativeJdbcExtractor.getNativeResultSet(rs); } //结果查询出来后,这里直接调用ResultSetExtractor接口的extractData对Resultset进行转换 return rse.extractData(rsToUse); } finally { JdbcUtils.closeResultSet(rs); if (pss instanceof ParameterDisposer) { ((ParameterDisposer) pss).cleanupParameters(); } } } }); }
从代码中可以看到,在excute函数的第二个参数中直接创建了PreparedStatementCallback的回调实例,里面首先进行结果查询,得到resultset结果集。然后调用传进来的ResultSetExtractor对结果集进行转换。
如果query的回调参数是RowCallbackHandler类型。如:
public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException { //使用ResultSetExtractor接口的实现类RowCallbackHandlerResultSetExtractor将RowCallbackHandler进行封装 query(sql, pss, new RowCallbackHandlerResultSetExtractor(rch)); }可以看到对于RowCallbackHandler使用了ResultSetExtractor接口的实现类RowCallbackHandlerResultSetExtractor将RowCallbackHandler进行封装。其中RowCallbackHandlerResultSetExtractor的具体实现如下:
private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<Object> { private final RowCallbackHandler rch; public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) { this.rch = rch; } public Object extractData(ResultSet rs) throws SQLException { while (rs.next()) { this.rch.processRow(rs); } return null; } }
可以看到在实现的extractData函数中对resultset结果集进行逐行便利,调用RowCallbackHandler的processRow函数进行逐行处理结果。
所以RowCallbackHandler的作用是对结果集中的一行数据进行处理。每一次调用只处理一行数据。最终的结果RowCallbackHandlerResultSetExtractor不负责保存和返回,而是由RowCallbackHandler的实现类自己负责保存。因此query函数返回值为void。
第三种RowMapper<T>回调参数类型,如:
public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException { //使用ResultSetExtractor接口的实现类RowMapperResultSetExtractor将RowMapper<T>进行封装 return query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper)); }同样是使用了ResultSetExtractor接口的实现类RowMapperResultSetExtractor对RowMapper<T>进行了封装。RowMapperResultSetExtractor的实现如下:
public class RowMapperResultSetExtractor<T> implements ResultSetExtractor<List<T>> { private final RowMapper<T> rowMapper; private final int rowsExpected; /** * Create a new RowMapperResultSetExtractor. * @param rowMapper the RowMapper which creates an object for each row */ public RowMapperResultSetExtractor(RowMapper<T> rowMapper) { this(rowMapper, 0); } /** * Create a new RowMapperResultSetExtractor. * @param rowMapper the RowMapper which creates an object for each row * @param rowsExpected the number of expected rows * (just used for optimized collection handling) */ public RowMapperResultSetExtractor(RowMapper<T> rowMapper, int rowsExpected) { Assert.notNull(rowMapper, "RowMapper is required"); this.rowMapper = rowMapper; this.rowsExpected = rowsExpected; } public List<T> extractData(ResultSet rs) throws SQLException { List<T> results = (this.rowsExpected > 0 ? new ArrayList<T>(this.rowsExpected) : new ArrayList<T>()); int rowNum = 0; while (rs.next()) { //对结果集调用RowMapper<T>的mapRow函数进行逐行处理,extractData负责对所有行的处理结果进行保存。 //RowMapper<T>的mapRow函数将返回每一行的数据处理为T类型的对象实例后返回 results.add(this.rowMapper.mapRow(rs, rowNum++)); } return results; } }
从代码中可以看到extractData函数调用RowMapper<T>的mapRow函数对结果集进行逐行处理,extractData负责对所有行的处理结果进行保存。RowMapper<T>的mapRow函数将返回每一行的数据处理为T类型的对象实例后返回。
这就是在使用RowMapper<T>和RowCallbackHandler上的区别。
下面再看下query函数的第一个参数,第一个参数基本上是两种类型,一个是String,一个是PreparedStatementCreator类型,都是用来表示对sql语句的封装。String类型的表示传进来的sql语句,大多数最终都会封装成PreparedStatementCreator接口类型,除了public <T> List<T> query(String sql, RowMapper<T> rowMapper)
public void query(String sql, RowCallbackHandler rch) throws DataAccessException
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException
在JdbcTemplate中定义了一个SimplePreparedStatementCreator内部类来实现PreparedStatementCreator接口。
/**
* Simple adapter for PreparedStatementCreator, allowing to use a plain SQL statement.
*/
private static class SimplePreparedStatementCreator implements PreparedStatementCreator, SqlProvider {
private final String sql;
public SimplePreparedStatementCreator(String sql) {
Assert.notNull(sql, "SQL must not be null");
this.sql = sql;
}
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
return con.prepareStatement(this.sql);
}
public String getSql() {
return this.sql;
}
}
这个类很简单,基本上是将要调用的sql与PreparedStatement进行了封装。
对于query函数的另一个参数,可以看作是sql语句的赋值参数。这个参数有两种类型,一个是Object[],另一个是PreparedStatementSetter接口类型的参数。Object[]数组类型的参数会封装成ArgumentPreparedStatementSetter类。从这个接口和的名字也可以看出该类的作用。就是用来设置PreparedStatement的,用来对PreparedStatement进行赋值操作的。
**
* Simple adapter for {@link PreparedStatementSetter} that applies a given array of arguments.
*
* @author Juergen Hoeller
* @since 3.2.3
*/
public class ArgumentPreparedStatementSetter implements PreparedStatementSetter, ParameterDisposer {
private final Object[] args;
/**
* Create a new ArgPreparedStatementSetter for the given arguments.
* @param args the arguments to set
*/
public ArgumentPreparedStatementSetter(Object[] args) {
this.args = args;
}
public void setValues(PreparedStatement ps) throws SQLException {
if (this.args != null) {
for (int i = 0; i < this.args.length; i++) {
Object arg = this.args[i];
doSetValue(ps, i + 1, arg);
}
}
}
/**
* Set the value for prepared statements specified parameter index using the passed in value.
* This method can be overridden by sub-classes if needed.
* @param ps the PreparedStatement
* @param parameterPosition index of the parameter position
* @param argValue the value to set
* @throws SQLException
*/
protected void doSetValue(PreparedStatement ps, int parameterPosition, Object argValue) throws SQLException {
if (argValue instanceof SqlParameterValue) {
SqlParameterValue paramValue = (SqlParameterValue) argValue;
StatementCreatorUtils.setParameterValue(ps, parameterPosition, paramValue, paramValue.getValue());
}
else {
StatementCreatorUtils.setParameterValue(ps, parameterPosition, SqlTypeValue.TYPE_UNKNOWN, argValue);
}
}
public void cleanupParameters() {
StatementCreatorUtils.cleanupParameters(this.args);
}
}
现在理解了这几种基本的调用后,对于JdbcTemplate中实现的queryForList、queryForMap、queryForObject等函数就好理解了。基本上就是上面三种基本形式的再封装以及相关接口的实例化实现。
相关文章推荐
- jdbc中的Statement和PreparedStatement接口对象
- Android之获取手机上的图片和视频缩略图thumbnails
- 数据库链接字符串查询网站
- 一个jar包里的网站
- 一个jar包里的网站之文件上传
- 一个jar包里的网站之返回对媒体类型
- DB2实例管理
- DB2实例管理
- 保障MySQL数据安全的14个最佳方法
- mysql问答汇集
- Spring整合Quartz(JobDetailBean方式)
- Spring整合Quartz(JobDetailBean方式)
- 第三章 数据库备份和还原
- 创建一个空的IBM DB2 ECO数据库的方法
- Access 2000 数据库 80 万记录通用快速分页类
- 开通一个数据库失败的原因的和解决办法
- 一个简单的asp数据库操作类
- CentOS下DB2数据库安装过程详解
- EasyASP v1.5发布(包含数据库操作类,原clsDbCtrl.asp)第1/2页