持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 26 天,点击查看活动详情
执行 SQL
那参数设置完成之后,接下来我们还剩最后两步,执行sql和封装返回结果
执行 SQL 语句比较简单,我们只需要调用 executeQuery() 方法就可以执行 SQL 语句,并且把查询的结果封装在 ResultSet 对象中。
public class SimpleExecutor implements Executor {
@Override
public <E> List<E> query(Configuration configuration, MapperStatement mapperStatement, Object... params) throws Exception {
//...
//执行 SQL 语句
ResultSet resultSet = preparedStatement.executeQuery();
//...
}
//..
}
封装返回结果集
封装返回结果的实现思路就是对 resultSet 进行遍历,取出 resultSet 里面查询出来字段值,把这些字段值按照映射关系封装成一个实体对象,这个就是我们接下来要完成业务。
至于如何把 resultSet 查询结果集中的这些字段值封装到哪个实体中,我们在编写映射配置文件时,其实已经指定了我们当前这条 SQL 语句,它需要把查询结果封装到哪个实体中。
使用 while 循环遍历 resultSet 结果集。在遍历的过程,首先取出 resultSet 中的元数据,那为什么要取它的一个元数据呢?因为这个元数据中包含了我们查询数据库表中字段的名称,也就是说我们可以借助元数据获取到查询结果的字段名称,因为这个字段名称在下面操作中要使用,所有先来获取到这个元数据。
接着,使用 for 循环获取数据库表中的所有字段。其中,在 for 循环中,把变量的值初始设置为 1,原因是获取数据库表中字段名称遍历时,它的下标要从 1 开始。
getColumnCount() 方法获取查询结果中列的个数。比例 user 表中有 1 列数据,在查询结果中也是 1 列数据,此时 getColumnCount() 的值就是 1。
getColumnName() 这个方法获取数据库表中的字段名称。获取到列名之后,就可以根据列名在 resultSet 集合中获取对应的值。 接着,使用反射机制,根据数据库表字段和实体中的属性对应关系,完成封装。
前面我们在创建数据库表和实体的时,实体中的属性名不能随便写,必须要和表中的字段名称一致,才能根据 getColumnName() 方法去实体中找到具体封装的属性。
使用 new 关键字 PropertyDescriptor 对象 PropertyDescriptor 对象实现了哪些功能,首先,在创建这个对象时,需要传递两个参数,一个是字段名(columnName),另一个是目前需要封装的实体对象。
目前需要封装的实体对象还没有,那么,如何才能获取到当前这个实体对象,其实要封装的实体的全路径在映射配置文件中已经配置好了,现在我们应该根据全路径名称,再根据名称获取对应的 Class 对象。具体代码实现如下:
//...
String resultType = mapperStatement.getResultType();
Class<?> resultTypeCalss = getClassType(resultType);
//...
接着,解释 PropertyDescriptor 类, 这个类是内省库中的一个类,我们可以利用它的有参构造先把这个对象创建出来。PropertyDescriptor 描述了一个JavaBean 属性的一对访问方法即 getter和setter。常用的构造方法是 PropertyDescriptor(String propertyName,Class<?> beanClass),propertyName 就是属性的名称,beanClass 就是这个属性对应属于哪个对象的 Class。
OK,到目前为止,返回结果集封装完成了。但是最终返回值是 List 集合,所以我们需要把封装好的这个实体对象存进一个集合中,需要再来去创建一个集合,把封装好的这个o存进这个集合中。
public class SimpleExecutor implements Executor {
@Override
public <E> List<E> query(Configuration configuration, MapperStatement mapperStatement, Object... params) throws Exception {
//..
// 6.封装返回结果集
String resultType = mapperStatement.getResultType();
Class<?> resultTypeCalss = getClassType(resultType);
Object o = resultTypeCalss.newInstance();
ArrayList<Object> objects = new ArrayList<>();
while (resultSet.next()){
// 获取元数据
ResultSetMetaData metaData = resultSet.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
// 获取字段名称
String columnName = metaData.getColumnName(i);
// 获取到字段值
Object object = resultSet.getObject(columnName);
//使用反射机制,根据数据库表和实体的对应关系完成封装。
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeCalss);
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(o,object);
}
objects.add(o);
}
return (List<E>) objects;
}
//...
}