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

yizhihongxing

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日

相关文章

  • Java中的注解是什么?

    Java中的注解(Annotation)是一种元数据形式的标记,用于提供给编译器或运行时环境运行时关于程序代码元素的数据。注解可以在Java代码中添加元数据,以提供更多的信息,包括代码作者、版本号、参数值、方法名称等。注解是一个与类、方法、属性、参数等一样的Java程序元素。 Java中的注解语法如下: @AnnotationName(parameterNa…

    Java 2023年4月27日
    00
  • 详解Java使用JMH进行基准性能测试

    详解Java使用JMH进行基准性能测试 性能测试对于Java应用程序的开发和优化是至关重要的。在Java中,可以使用JMH框架进行严密的基准测试,以确保在实际生产环境中获得最高的性能和最小的延迟。 介绍JMH框架 JMH是一个专业级的基准测试框架,它可以提供准确的基准测试结果。它提供了多种的方式来测试不同的Java代码片段,包括方法调用、对象实例化、算法等。…

    Java 2023年5月26日
    00
  • 一篇文章带你了解Java SpringBoot Nacos

    一篇文章带你详解Java SpringBoot Nacos 什么是SpringBoot? SpringBoot是一个基于Spring框架的快速开发框架,它简化了Spring的配置、发布和部署过程,提高了开发效率。同时SpringBoot也集成了大量常用的库和插件,方便开发人员开箱即用。如果您是Java开发者,使用SpringBoot无疑是提高开发效率的好选择…

    Java 2023年5月20日
    00
  • Java中的异常处理如何提高程序性能?

    Java中的异常处理机制是保证程序健壮性和可靠性的一项重要特性。合理利用异常处理可以提高程序的性能和可读性,下面我们来详细讲解Java中的异常处理如何提高程序性能。 1. 不要滥用异常 异常处理机制是有代价的,如果频繁抛出异常,可能会造成性能问题。因为抛出异常需要创建新的异常对象,这需要时间和内存。所以,在代码编写时,我们应该避免不必要的异常抛出,只在必要时…

    Java 2023年4月27日
    00
  • WIN2003上Apache2+IIS6+Tomcat5之多站点完美配置篇

    接下来我将为你详细讲解“WIN2003上Apache2+IIS6+Tomcat5之多站点完美配置篇”的完整攻略。 什么是Apache,IIS以及Tomcat Apache Apache是一款常用的Web服务器软件,支持多种操作系统和编程语言。它是自由软件,采用了Apache许可证,因此可以免费使用、复制、修改和分发。Apache的优点是简单易用、配置灵活、性…

    Java 2023年5月19日
    00
  • 分代垃圾回收的作用是什么?

    以下是关于分代垃圾回收的详细讲解: 什么是分代垃圾回收? 分代垃圾回收是一种常见的垃圾回收算法。其原理是将内存空间分为不同的代,每一代对象具有不同的生命周期。在程序运行过程中,垃圾回收器会根据对象的生命周期将其分配到不同的代中,然后对不同代的对象采用不同的垃圾回收策略,以提高垃圾回收的效率和性能。 分代垃圾回收通常将内存空间分为三代:年轻代、中年代和老年代。…

    Java 2023年5月12日
    00
  • Java Spring 循环依赖解析

    下面是“Java Spring 循环依赖解析”的完整攻略。 什么是循环依赖? 在 Spring 容器中,如果两个或多个 Bean 相互依赖,且这种互相依赖形成了环路,就会出现循环依赖。 例如,BeanA依赖BeanB,而BeanB又依赖BeanA,则会形成一个循环依赖。 如何解决循环依赖? Spring 解决循环依赖的方式称为循环依赖解析。当 Spring …

    Java 2023年5月20日
    00
  • 图解排序算法之希尔排序Java实现

    让我来详细讲解一下“图解排序算法之希尔排序Java实现”的完整攻略。 1. 前言 本篇攻略摘自江南蓝山的“图解排序算法”系列文章,讲解希尔排序在Java中的实现方法。 2. 希尔排序简介 希尔排序是一种基于插入排序的快速排序算法,也被称为“缩小增量排序”。它的基本思想是将待排序的数组按照一定的间隔分成若干个子序列,然后对每个子序列分别进行插入排序。随着间隔不…

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