咱们上次对执行增删改的操作进行分析以后,这次则来对查询进行流程梳理把~
源码解析
接下来则来对JdbcTemplate的query方法进行一个源码解析吧~
eg:
List<User> users = template.query(sql,new BeanPropertyRowMapper<User>(User.class),params.toArray())
这里我们来分析下为什么返回值是List<User>
第一步是创建JdbcTemplate对象,传入数据源,进入构造方法查看
JdbcTemplate.java
1
2
3
4
|
public JdbcTemplate(DataSource dataSource) {
setDataSource(dataSource);
afterPropertiesSet();
}
|
JdbcAccessor.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private DataSource dataSource;
private boolean lazyInit = true ;
public void setDataSource(DataSource dataSource) {
this .dataSource = dataSource;
}
public DataSource getDataSource() {
return this .dataSource;
}
public boolean isLazyInit() {
return this .lazyInit;
}
public void afterPropertiesSet() {
if (getDataSource() == null ) {
throw new IllegalArgumentException( "Property 'dataSource' is required" );
}
if (!isLazyInit()) {
getExceptionTranslator();
}
}
|
通过上面代码来看说白了就是用来初始化我们JdbcTemplate对象的,当然也做了不少操作,比如要判断是够有提供dataSource对象
第二步是调用对应的query方法,把sql和参数传入最后接收响应结果
创建完我们的jdbcTemplate对象后那么接下来才真正的进入到我们执行查询的query方法中~
JdbcTemplate.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
//---------
//标注五
return (List) this .query((String)sql, (Object[])args, (ResultSetExtractor)( new RowMapperResultSetExtractor(rowMapper)));
}
...
public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {
return this .query(sql, this .newArgPreparedStatementSetter(args), rse);
}
...
public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException {
return this .query((PreparedStatementCreator)( new JdbcTemplate.SimplePreparedStatementCreator(sql)), (PreparedStatementSetter)pss, (ResultSetExtractor)rse);
}
...
//---------
//标注一
public <T> T query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws DataAccessException {
Assert.notNull(rse, "ResultSetExtractor must not be null" );
this .logger.debug( "Executing prepared SQL query" );
//---------
//标注二
return this .execute(psc, new PreparedStatementCallback<T>() {
public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
//---------
//标注三
ResultSet rs = null ;
Object var4;
try {
if (pss != null ) {
//将预编译的PreparedStatement对象和sql语句的?占位符和实际参数进行绑定
pss.setValues(ps);
}
//获取结果集
rs = ps.executeQuery();
ResultSet rsToUse = rs;
if (JdbcTemplate. this .nativeJdbcExtractor != null ) {
rsToUse = JdbcTemplate. this .nativeJdbcExtractor.getNativeResultSet(rs);
}
//---------
//标注四
var4 = rse.extractData(rsToUse);
} finally {
JdbcUtils.closeResultSet(rs);
if (pss instanceof ParameterDisposer) {
((ParameterDisposer)pss).cleanupParameters();
}
}
return var4;
}
});
}
|
通过上面代码来看,我们很容易就能够追到标注一的地方,而这里也是触发查询操作的开始,接下来咱们则来对这个方法进行一个详细的剖析,看到标注二这里相信大家就能感到很眼熟了,因为上次我们在追update方法的源码时最终也会执行到execute方法,在这我们就直接将execute方法执行原理不在复述一遍了.我们直接从标注三开始,因为doInPreparedStatement方法的返回值其实就是最终的返回值
标注四
首先先来看下rse对象
ResultSetExtractor<T> rse
这个对象是在标注五的地方进行的初始化,(ResultSetExtractor)(new RowMapperResultSetExtractor(rowMapper)),通过这段代码我们可以看到我们将RowMapperResultSetExtractor对象强制转换成ResultSetExtractor,但是创建RowMapperResultSetExtractor对象的时候我们传入了一个rowMapper对象,这个对象,则是咱们查询的时候传入的BeanPropertyRowMapper,接下来咱们从RowMapperResultSetExtractor开始分析
标注五
RowMapperResultSetExtractor
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public class RowMapperResultSetExtractor<T> implements ResultSetExtractor<List<T>> {
private final RowMapper<T> rowMapper;
private final int rowsExpected;
public RowMapperResultSetExtractor(RowMapper<T> rowMapper) {
this (rowMapper, 0 );
}
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( this .rowsExpected) : new ArrayList();
int var3 = 0 ;
while (rs.next()) {
results.add( this .rowMapper.mapRow(rs, var3++));
}
return results;
}
}
|
通过上面的代码我们看到该类中保存了RowMapper和rowsExpected,因为走的是一个参数的构造所以rowsExpected为0,因此标注4中的rse对象的实际对象为RowMapperResultSetExtractor,而rse.extractData(rsToUse);方法则进入
标注六
List<T> results = this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList();
经过之前的分析,rowsExpected默认为0,所以执行三元表达式的后半部分,创建一个新的ArrayList
while(rs.next()) {
//---------
//标注7
results.add(this.rowMapper.mapRow(rs, var3++));
}
这段代码中则是将结果集的每条结果添加到目标ArrayList中,因此我们又把注意力转向了this.rowMapper.mapRow(rs, var3++)
标注七
rowMapper这个对象实际类型为BeanPropertyRowMapper
BeanPropertyRowMapper初始化走的构造
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public BeanPropertyRowMapper(Class<T> mappedClass) {
this .initialize(mappedClass);
}
protected void initialize(Class<T> mappedClass) {
this .mappedClass = mappedClass;
this .mappedFields = new HashMap();
this .mappedProperties = new HashSet();
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass);
PropertyDescriptor[] var3 = pds;
int var4 = pds.length;
for ( int var5 = 0 ; var5 < var4; ++var5) {
PropertyDescriptor pd = var3[var5];
if (pd.getWriteMethod() != null ) {
this .mappedFields.put( this .lowerCaseName(pd.getName()), pd);
String underscoredName = this .underscoreName(pd.getName());
if (! this .lowerCaseName(pd.getName()).equals(underscoredName)) {
this .mappedFields.put(underscoredName, pd);
}
this .mappedProperties.add(pd.getName());
}
}
}
|
上面用到了内省,这块简单介绍下,就是通过内省我们可以轻松获取到一个类的属性和相关get/set方法,只要属性和相关方法对象,那么我们就可以通过反射的形式将结果集中的数据封装到该对象中,而上面代码只是进行了参数的初始化方便mapRow方法进行封装而已
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
Assert.state( this .mappedClass != null , "Mapped class was not specified" );
//---------
//标注八:初始化目标对象
T mappedObject = BeanUtils.instantiate( this .mappedClass);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
this .initBeanWrapper(bw);
//结果集元数据
ResultSetMetaData rsmd = rs.getMetaData();
//获取一共多少列
int columnCount = rsmd.getColumnCount();
Set<String> populatedProperties = this .isCheckFullyPopulated() ? new HashSet() : null ;
//---------
//标注九:初始化目标对象
//循环遍历每一列,将每列的值封装到实体bean的指定属性中
for ( int index = 1 ; index <= columnCount; ++index) {
String column = JdbcUtils.lookupColumnName(rsmd, index);
String field = this .lowerCaseName(column.replaceAll( " " , "" ));
PropertyDescriptor pd = (PropertyDescriptor) this .mappedFields.get(field);
if (pd == null ) {
if (rowNumber == 0 && this .logger.isDebugEnabled()) {
this .logger.debug( "No property found for column '" + column + "' mapped to field '" + field + "'" );
}
} else {
try {
//获取该列的数据,同时找到判断具体数据类型
Object value = this .getColumnValue(rs, index, pd);
if (rowNumber == 0 && this .logger.isDebugEnabled()) {
this .logger.debug( "Mapping column '" + column + "' to property '" + pd.getName() + "' of type [" + ClassUtils.getQualifiedName(pd.getPropertyType()) + "]" );
}
try {
//将Bean的属性和获取到的值进行绑定
bw.setPropertyValue(pd.getName(), value);
} catch (TypeMismatchException var14) {
if (value != null || ! this .primitivesDefaultedForNullValue) {
throw var14;
}
if ( this .logger.isDebugEnabled()) {
this .logger.debug( "Intercepted TypeMismatchException for row " + rowNumber + " and column '" + column + "' with null value when setting property '" + pd.getName() + "' of type [" + ClassUtils.getQualifiedName(pd.getPropertyType()) + "] on object: " + mappedObject, var14);
}
}
if (populatedProperties != null ) {
populatedProperties.add(pd.getName());
}
} catch (NotWritablePropertyException var15) {
throw new DataRetrievalFailureException( "Unable to map column '" + column + "' to property '" + pd.getName() + "'" , var15);
}
}
}
if (populatedProperties != null && !populatedProperties.equals( this .mappedProperties)) {
throw new InvalidDataAccessApiUsageException( "Given ResultSet does not contain all fields necessary to populate object of class [" + this .mappedClass.getName() + "]: " + this .mappedProperties);
} else {
return mappedObject;
}
}
|
标注八
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
Assert.notNull(clazz, "Class must not be null" );
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface" );
} else {
try {
return clazz.newInstance();
} catch (InstantiationException var2) {
throw new BeanInstantiationException(clazz, "Is it an abstract class?" , var2);
} catch (IllegalAccessException var3) {
throw new BeanInstantiationException(clazz, "Is the constructor accessible?" , var3);
}
}
}
|
ok,到此为止我们就能分析出来,在这段for循环中才是将实体Bean对象中的属性值和rs中每列的数据进行绑定,从而完成将查询到的数据封装到Bean的过程.当然,这块因为篇幅的原因可能有点粗糙,但是主要起到一个抛砖引玉的作用~~~