Mybatis输入输出映射及动态SQL Review

Mybatis输入输出映射及动态SQL Review

Mybatis是一个基于Java的持久化框架,支持定制化SQL、存储过程以及高级映射。在Mybatis中,输入输出映射是指将Java对象与SQL语句的参数或结果集进行转换的机制,而动态SQL则可根据需要构建不同的SQL语句。

输入输出映射

输入输出映射主要涉及Mybatis中的ParameterHandler和ResultSetHandler。ParameterHandler将Java对象转换为SQL参数,而ResultSetHandler则将SQL查询结果转换为Java对象。

ParameterHandler

ParameterHandler位于org.apache.ibatis.executor.parameter包中,它是实现参数设置的接口。Mybatis提供了DefaultParameterHandler和MapParameterHandler两种默认的实现,如果需要自定义ParameterHandler,则需要实现ParameterHandler接口。下面以DefaultParameterHandler为例进行说明:

public class DefaultParameterHandler implements ParameterHandler {
  private TypeHandlerRegistry typeHandlerRegistry;

  ...

  @Override
  public void setParameters(PreparedStatement ps) throws SQLException {
    Object[] args = parameterObject == null ? new Object[0] : (Object[]) parameterObject;
    for (int i = 0; i < args.length; i++) {
      TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(args[i].getClass());
      typeHandler.setParameter(ps, i + 1, args[i], parameterMapping.getJdbcType());
    }
  }
}

DefaultParameterHandler将Java对象数组中的每个对象,使用TypeHandler转换成对应的SQL参数,并通过PreparedStatement进行设置。setParameters方法即为由Mybatis负责调用的接口,其中包含PreparedStatement对象,因此可以在自定义ParameterHandler中使用setParameters方法进行参数设置。

ResultSetHandler

ResultSetHandler位于org.apache.ibatis.executor.resultset包中,是ResultMap映射实现的核心。Mybatis提供了DefaultResultSetHandler、FastResultSetHandler、MapResultSetHandler和XMLResultSetHandler等默认的实现,如果需要自定义ResultSetHandler,则需要实现ResultSetHandler接口。下面以DefaultResultSetHandler为例进行说明:

public class DefaultResultSetHandler implements ResultSetHandler {
  private final Executor executor;
  private final Configuration configuration;
  private final MappedStatement mappedStatement;
  private final RowBounds rowBounds;
  private final ResultHandler resultHandler;
  private final BoundSql boundSql;
  private final TypeHandlerRegistry typeHandlerRegistry;

  ...

  @Override
  public <E> List<E> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<E> list = new ArrayList<>();

    ResultSetWrapper rsw = getResultSetWrapper(stmt);
    try {
      handleResultSet(rsw, list);
    } finally {
      closeResultSet(rsw.getResultSet());
    }

    return list;
  }

  private ResultSetWrapper getResultSetWrapper(Statement stmt) throws SQLException {
    ResultSet rs = stmt.getResultSet();
    while (rs == null) {
      if (stmt.getMoreResults()) {
        rs = stmt.getResultSet();
      } else {
        if (stmt.getUpdateCount() == -1) {
          break;
        }
      }
    }
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }

  private void handleResultSet(ResultSetWrapper rsw, List<Object> list) throws SQLException {
    if (rsw == null) {
      return;
    }
    try {
      // 将ResultSet结果集使用TypeHandler转换成Java对象
      final ResultSetMetaData metaData = rsw.getMetaData();
      final TypeHandler<Object> typeHandler = typeHandlerRegistry.getTypeHandler(Object.class);

      while (rsw.getResultSet().next()) {
        // 创建映射的结果集对象
        final Object resultObject = createResultObject(rsw, mappedStatement.getResultMap());
        if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultObject.getClass())) {
          // 查找该结果集对象对应的TypeHandler
          final MetaObject metaObject = configuration.newMetaObject(resultObject);
          final List<ResultMapping> unmappedResultList = new ArrayList<ResultMapping>();
          final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, null);
          for (ResultMapping resultMapping : resultMap.getResultMappings()) {
            // 根据列名和Java属性名等信息,查找对应的TypeHandler进行对象转换
            String column = resultMapping.getColumn();
            // ResultMapping对应的Java属性名称
            String property = resultMapping.getProperty();
            TypeHandler<?> typeHandlerImpl = null;
            if (resultMapping.getNestedResultMapId() != null) {
              // 这里没有进行更深一层次的映射处理
              typeHandlerImpl = new NestedResultSetHandler(resultMapping.getNestedResultMap(), rsw, rowBounds, resultHandler, typeHandlerRegistry, mappedColumnNames, configuration).getTypeHandler(property);
            } else if (resultMapping.getResultSet() != null) {
              // 这里没有进行更深一层次的映射处理
              typeHandlerImpl = new ResultSetTypeHandler(resultMapping.getResultSet(), rsw, rowBounds, resultHandler, typeHandlerRegistry, mappedColumnNames, configuration).getTypeHandler(property);
            } else if (column != null && !"".equals(column.trim())) {
              JdbcType jdbcType = resultMapping.getJdbcType();
              if (jdbcType == null) {
                jdbcType = configuration.getJdbcTypeForNull();
              }
              // 根据列名和Java属性名等信息,查找对应的TypeHandler进行对象转换
              typeHandlerImpl = rsw.getTypeHandler(jdbcType, column);
            } else {
              typeHandlerImpl = typeHandlerRegistry.getTypeHandler(resultMapping.getJavaType());
            }
            if (typeHandlerImpl == null) {
              // 如果没有对应的TypeHandler,则将结果映射设置为null
              unmappedResultList.add(resultMapping);
            } else {
              // 进行结果集对象到Java对象的转换
              Object value = typeHandlerImpl.getResult(rsw.getResultSet(), property);
              // 判断目标转换类型是否是Java基本类型,如果是,则将结果集中null值转换为默认值
              if (value == null && configuration.isCallSettersOnNulls()) {
                Class<?> javaType = resultMapping.getJavaType();
                if (javaType == int.class || javaType == short.class || javaType == long.class || javaType == byte.class) {
                  value = 0;
                } else if (javaType == float.class || javaType == double.class) {
                  value = 0.0;
                } else if (javaType == boolean.class) {
                  value = false;
                }
              }
              metaObject.setValue(property, value);
            }
          }
          if (unmappedResultList.size() > 0) {
            // 将未映射的结果集设置为null
            handleUnmappedProperties(metaObject, unmappedResultList, rsw.getResultSet());
          }
          list.add(resultObject);
        } else {
          Object value = typeHandler.getResult(rsw.getResultSet(), 1);
          list.add(value);
        }
      }
    } finally {
      // 将ResultSet关闭
      closeResultSet(rsw.getResultSet());
    }
  }
}

DefaultResultSetHandler中的handleResultSets方法是Mybatis使用ResultSet构建Java对象的核心方法。handleResultSets方法包含ResultSetResultSetWrapper和RowBounds等参数,通过调用createResultObject、getTypeHandler、getResult等方法,将ResultSet结果集中的每一行数据映射为Java对象,最终返回Java对象的List集合。

动态SQL

动态SQL指的是运行时根据条件构建SQL语句,主要包括if、choose、when、otherwise、foreach、bind等元素。Mybatis支持通过XML方式或注解方式实现动态SQL。

动态SQL示例1:if元素
if元素可以根据条件进行SQL语句的拼接,例如根据搜索条件进行模糊查询。下面是一个根据用户名模糊查询用户列表的示例代码:

<select id="selectUsersByNameLike" resultMap="UserResultMap">
  SELECT * FROM users
  <where>
    <if test="name != null and name != ''">
      AND name LIKE CONCAT('%', #{name}, '%')
    </if>
  </where>
  ORDER BY id
</select>

在XML配置文件中,使用if元素进行参数判断,根据判断结果来拼接SQL语句。

动态SQL示例2:foreach元素
foreach元素可以进行迭代集合,对集合中的元素进行操作。下面是一个根据ID列表批量查询用户信息的示例代码:

<select id="selectUsersByIdList" resultMap="UserResultMap">
  SELECT * FROM users
  WHERE id IN
  <foreach item="item" index="index" collection="idList" open="(" separator="," close=")">
    #{item}
  </foreach>
</select>

在XML配置文件中,使用foreach元素遍历idList列表,将每个元素拼接到SQL语句中,并执行查询。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Mybatis输入输出映射及动态SQL Review - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • SpringBoot+SpringSecurity 不拦截静态资源的实现

    一、背景 在开发 Web 应用时,我们通常需要使用 SpringBoot 和 SpringSecurity 进行开发,其中 SpringSecurity 用于处理安全相关的逻辑。在使用 SpringSecurity 进行开发时,有时候我们需要对某些 URL 进行访问控制,但是又不希望对一些静态资源进行拦截,否则会影响应用性能。 本篇文章将为大家介绍如何使用 …

    Java 2023年5月20日
    00
  • Java异常处理try catch的基本使用

    Java异常处理try catch的基本使用 在Java编程中,程序执行过程中可能出现各种错误,例如文件找不到,数组越界等,这些错误被称为异常。异常处理是Java编程中最基本的编程技巧之一。Java异常处理try catch提供了一种结构化的异常处理方法,可以使程序更加健壮,便于维护。 什么是Java异常处理try catch Java异常处理try cat…

    Java 2023年5月27日
    00
  • JDBC工具类实现登录功能

    以下是“JDBC工具类实现登录功能”的完整攻略: 1. 什么是JDBC工具类 JDBC是Java Database Connectivity的缩写,是Java标准中用于操作关系型数据库的API。JDBC提供了一组用于连接数据库、执行SQL语句和处理结果集的类和接口。为了方便使用JDBC,我们可以创建一个JDBC工具类,该类提供了一组常用的方法,封装了JDBC…

    Java 2023年5月20日
    00
  • Struts2 的国际化实现方式示例

    下面将结合代码示例详细讲解 Struts2 的国际化实现方式。 一、国际化实现的基本原理 Struts2 的国际化实现是通过多资源包机制来实现的。在一个 web 应用程序中,我们可以定义多个资源包,每个资源包对应不同的语言/国家 locale,当系统的 locale 和资源包的 locale 匹配时,Struts2 会自动使用该 locale 对应的资源文件…

    Java 2023年5月20日
    00
  • Lombok和MapStruct整合详情

    Lombok和MapStruct是两个非常实用的Java开发工具,其中Lombok可以减少编写代码的麻烦,而MapStruct则可以生成JavaBean之间的映射关系,因此它们在项目中的应用十分广泛。下面将详细讲解Lombok和MapStruct整合的攻略。 Lombok和MapStruct整合:步骤说明 首先在项目的pom.xml文件中导入Lombok和M…

    Java 2023年5月26日
    00
  • java读写ini文件、FileOutputStream问题

    要在Java中读写ini文件,有以下几个步骤: 引入ini4j库 ini4j是一个开源的Java类库,主要用于解析INI文件。 在Maven项目中,可以在pom.xml文件中添加以下依赖: <dependency> <groupId>org.ini4j</groupId> <artifactId>ini4j&l…

    Java 2023年5月19日
    00
  • java对指定目录下文件读写操作介绍

    Java 对指定目录的文件读写操作介绍 Java 中对于指定目录的文件读写操作可以通过 Java IO 包中的类实现,这里介绍如何使用 Java IO 对指定目录下的文件进行读写操作。 读取指定目录下的文件 可以通过 Java 文件类(File)中的方法获取指定目录下的文件列表,在遍历文件列表过程中,通过流的方式读取每个文件的内容。示例代码如下: impor…

    Java 2023年5月20日
    00
  • Java Apache Commons报错“TransformerFactoryConfigurationError”的原因与解决方法

    “TransformerException”是Java的ApacheCommons类库中的一个异常,通常由以下原因之一引起: XML格式错误:如果XML格式不正确,则可能会出现此异常。例如,可能会缺少必需的元素或属性。 XSLT格式错误:如果XSLT格式不正确,则可能会出现此异常。例如,可能会使用错误的XSLT模板或模板配置错误。 以下是两个实例: 例1 如…

    Java 2023年5月5日
    00
合作推广
合作推广
分享本页
返回顶部