实现 SQL 语句执行和返回结果集封装

487 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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;
   }
   //...
}