Mybatis结果集映射与生命周期源码分析

发布时间:2022-10-12 10:34:41 作者:iii
来源:亿速云 阅读:113

Mybatis结果集映射与生命周期源码分析

1. 引言

MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

在 MyBatis 中,结果集映射是一个非常重要的功能,它能够将数据库查询的结果集映射到 Java 对象中。本文将深入分析 MyBatis 的结果集映射机制以及其生命周期管理。

2. MyBatis 结果集映射

2.1 结果集映射的基本概念

在 MyBatis 中,结果集映射是指将数据库查询的结果集映射到 Java 对象的过程。MyBatis 提供了多种方式来实现结果集映射,包括使用 XML 配置、注解以及自动映射。

2.2 结果集映射的类型

MyBatis 支持以下几种结果集映射方式:

  1. 自动映射:MyBatis 会根据查询结果的列名自动映射到 Java 对象的属性上。这种方式适用于简单的映射场景。
  2. XML 配置映射:通过 XML 配置文件手动指定结果集与 Java 对象的映射关系。这种方式适用于复杂的映射场景。
  3. 注解映射:通过注解直接在 Java 接口或方法上指定结果集与 Java 对象的映射关系。这种方式适用于简单的映射场景。

2.3 结果集映射的实现

MyBatis 的结果集映射是通过 ResultSetHandler 接口来实现的。ResultSetHandler 接口的主要职责是将 ResultSet 对象转换为 Java 对象。

public interface ResultSetHandler {
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;
  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
  void handleOutputParameters(CallableStatement cs) throws SQLException;
}

DefaultResultSetHandler 类中,MyBatis 实现了 ResultSetHandler 接口,并提供了默认的结果集映射逻辑。

2.4 结果集映射的源码分析

2.4.1 自动映射

自动映射是 MyBatis 默认的结果集映射方式。MyBatis 会根据查询结果的列名自动映射到 Java 对象的属性上。

public class DefaultResultSetHandler implements ResultSetHandler {
  // 自动映射逻辑
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    // 根据 ResultMap 创建结果对象
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();
    final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // 自动映射属性
        final String property = propertyMapping.getProperty();
        final Class<?> propertyType = propertyMapping.getJavaType();
        final Object value = getPropertyMappingValue(rsw.getResultSet(), propertyMapping, columnPrefix);
        if (value != null) {
          MetaObject metaObject = configuration.newMetaObject(resultObject);
          metaObject.setValue(property, value);
        }
      }
    }
    return resultObject;
  }
}

2.4.2 XML 配置映射

XML 配置映射是通过 ResultMap 元素来定义的。ResultMap 元素可以指定结果集与 Java 对象的映射关系。

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name" />
  <result property="email" column="user_email" />
</resultMap>

DefaultResultSetHandler 类中,MyBatis 会根据 ResultMap 的定义来映射结果集。

public class DefaultResultSetHandler implements ResultSetHandler {
  // XML 配置映射逻辑
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    // 根据 ResultMap 创建结果对象
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();
    final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // 根据 ResultMapping 映射属性
        final String property = propertyMapping.getProperty();
        final Class<?> propertyType = propertyMapping.getJavaType();
        final Object value = getPropertyMappingValue(rsw.getResultSet(), propertyMapping, columnPrefix);
        if (value != null) {
          MetaObject metaObject = configuration.newMetaObject(resultObject);
          metaObject.setValue(property, value);
        }
      }
    }
    return resultObject;
  }
}

2.4.3 注解映射

注解映射是通过 @Results@Result 注解来定义的。@Results 注解可以指定结果集与 Java 对象的映射关系。

@Results({
  @Result(property = "id", column = "user_id"),
  @Result(property = "username", column = "user_name"),
  @Result(property = "email", column = "user_email")
})
@Select("SELECT user_id, user_name, user_email FROM users WHERE id = #{id}")
User getUserById(int id);

MapperAnnotationBuilder 类中,MyBatis 会根据注解的定义来生成 ResultMap

public class MapperAnnotationBuilder {
  // 注解映射逻辑
  private void parseStatement(Method method) {
    // 解析 @Results 注解
    final Results results = method.getAnnotation(Results.class);
    if (results != null) {
      parseResults(results);
    }
  }

  private void parseResults(Results results) {
    // 生成 ResultMap
    final ResultMap resultMap = new ResultMap.Builder(configuration, "id", type, resultMappings).build();
    configuration.addResultMap(resultMap);
  }
}

3. MyBatis 生命周期管理

3.1 MyBatis 生命周期概述

MyBatis 的生命周期管理主要包括以下几个阶段:

  1. 配置阶段:MyBatis 在启动时会加载配置文件,并初始化 Configuration 对象。
  2. SQL 执行阶段:MyBatis 在执行 SQL 语句时,会创建 SqlSession 对象,并通过 Executor 执行 SQL 语句。
  3. 结果集映射阶段:MyBatis 会将查询结果映射到 Java 对象中。
  4. 资源释放阶段:MyBatis 在执行完 SQL 语句后,会释放相关资源。

3.2 配置阶段

在配置阶段,MyBatis 会加载配置文件,并初始化 Configuration 对象。Configuration 对象是 MyBatis 的核心配置对象,它包含了所有的配置信息。

public class Configuration {
  // 配置信息
  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
  protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
  protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
}

3.3 SQL 执行阶段

在 SQL 执行阶段,MyBatis 会创建 SqlSession 对象,并通过 Executor 执行 SQL 语句。

public class DefaultSqlSession implements SqlSession {
  // SQL 执行逻辑
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
}

3.4 结果集映射阶段

在结果集映射阶段,MyBatis 会将查询结果映射到 Java 对象中。这一过程主要由 ResultSetHandler 接口的实现类 DefaultResultSetHandler 来完成。

public class DefaultResultSetHandler implements ResultSetHandler {
  // 结果集映射逻辑
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    final List<Object> multipleResults = new ArrayList<>();
    int resultSetCount = 0;
    ResultSetWrapper rsw = new ResultSetWrapper(stmt.getResultSet(), configuration);
    ResultMap resultMap = mappedStatement.getResultMaps().get(resultSetCount);
    while (rsw != null && resultMap != null) {
      // 处理结果集
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      resultMap = getNextResultMap(mappedStatement, resultMap, resultSetCount);
      resultSetCount++;
    }
    return collapseSingleResultList(multipleResults);
  }
}

3.5 资源释放阶段

在资源释放阶段,MyBatis 会释放相关资源,包括关闭 ResultSetStatementConnection 等。

public class DefaultSqlSession implements SqlSession {
  // 资源释放逻辑
  public void close() {
    try {
      executor.close(isCommitOrRollbackRequired(false));
      dirty = false;
    } finally {
      ErrorContext.instance().reset();
    }
  }
}

4. 总结

本文详细分析了 MyBatis 的结果集映射机制以及其生命周期管理。MyBatis 提供了多种结果集映射方式,包括自动映射、XML 配置映射和注解映射。MyBatis 的生命周期管理主要包括配置阶段、SQL 执行阶段、结果集映射阶段和资源释放阶段。通过深入理解 MyBatis 的结果集映射和生命周期管理,我们可以更好地使用 MyBatis 进行数据库操作。

推荐阅读:
  1. jdbc关于实现Mybatis结果集解析
  2. 如何使用Dapper处理多个结果集与多重映射实例教程

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mybatis

上一篇:Python淘宝或京东等秒杀抢购脚本怎么实现

下一篇:Laravel怎么进行路由分组

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》