MB查询结果映射过程源码解析

问题:

查询结果为空的时候为什么集合会是空集合,而对象是 NULL?

 

JDBC 中的 ResultSet 

在数据库中执行一条 Select 语句通常只能拿到一个 ResultSet,而结果集 ResultSet 是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象。结果集不仅仅具有存储的功能,同时还具有操纵数据的功能,可以完成对数据的更新等,可以通过 next() 方法将指针移动到下一行记录,然后通过 getXX() 方法来获取值

while(rs.next()){
    // 获取数据
    int id = rs.getInt(1);
    String name = rs.getString("name");
 
    System.out.println(id + "---" + name);
}

 

 MyBatis执行完一条select 语句,拿到ResultSet 结果集之后,会将其交给关联的ResultSetHandler 进行后续的映射处理。在MyBatis中只提供了一个ResultSetHandler接口实现,即DefaultResultSetHandler。

public interface ResultSetHandler {
 
    // 将ResultSet映射成Java对象
    <E> List<E> handleResultSets(Statement stmt) throws SQLException;
 
    // 将ResultSet映射成游标对象
    <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
 
    // 处理存储过程的输出参数
    void handleOutputParameters(CallableStatement cs) throws SQLException;
 
}

 

源码解析:

收获

  1. ResultSet 元数据中记录了 ResultSet 中每列的名称、对应的 Java 类型、Jdbctype类型以及每列对应的 TypeHandler

  2. 通过 RowBounds 指定 offset、limit 参数实现分页的效果。skipRows() 方法中的RowBounds 移动 ResultSet 的指针到指定的数据行,这样后续的映射操作就可以从这一行开始。通过 RowBounds 实现的分页功能实际上还是会将全部数据加载到 ResultSet 中,而不是只加载指定范围的数据所以RowBounds 实现的是一种“假分页"

  3. 不管是查单行记录还是多行记录,对于 Mybatis 来说都会放到 DefaultResultHandler 中去,而 DefaultResultHandler 又是用 List 存储结果。所以不管是集合类型还是普通对象,Mybatis 都会先初始化一个 List 存储结果,然后返回值为普通对象且查为空的时候,selectOne 会判断List的size是否为0,不为0则get(0),为0就return null,然后直接返回 NULL 值。而返回值为集合对象且查为空时,selectList 会把这个存储结果的 List 对象直接返回,此时这个 List 就是个空集合

posted @ 2025-07-03 11:42  complexlong  阅读(23)  评论(0)    收藏  举报