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日

相关文章

  • 配置pom.xml用maven打包java工程的方法(推荐)

    这里是配置pom.xml用maven打包Java工程的方法的完整攻略: 1. 确认构建环境 在开始配置pom.xml之前,建议确认以下环境是否已安装: JDK(Java Development Kit) Maven 确认环境安装情况: 打开终端或命令行 输入命令java -version,确认能够输出Java的版本信息 输入命令mvn -version,确认…

    Java 2023年5月20日
    00
  • Java IO及BufferedReader.readline()出现的Bug

    关于“Java IO及BufferedReader.readline()出现的Bug”,我们需要注意以下两点: 1. Java IO 中的缓存问题 Java的IO操作是基于缓存进行的,而很多读取函数如BufferedReader. readline()是以换行符作为结束标记的,但是我们在编写代码时常常忽略了特殊情况的处理,导致出现了缓存问题,例如一次读取操作…

    Java 2023年5月27日
    00
  • java身份证验证代码实现

    下面是 “java身份证验证代码实现”的完整攻略。 1. 身份证号码规则 身份证号码规则如下: 身份证号码为18位数字和字母(除最后一位是字母外) 前17位为地区码和出生日期码,最后一位为校验码 校验码计算方法: 取出前17位数字(地区码和出生日期码),按权重分别乘以7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2 对乘积求和 将和数除…

    Java 2023年5月19日
    00
  • Java统计字符串中字符出现次数的方法示例

    Java中统计字符串中字符出现次数的方法,可以使用HashMap(以字符为key,以出现次数为value)来实现。 具体步骤如下: 1.创建一个HashMap对象 Map<Character, Integer> charFrequency = new HashMap<Character, Integer>(); 这里使用了Java中的…

    Java 2023年5月27日
    00
  • Java实战之医院管理系统的实现

    Java实战之医院管理系统的实现 系统介绍 医院管理系统是一个综合性管理平台,它能够帮助医院管理各个方面的业务。该系统主要包含以下几个模块: 患者管理模块 患者管理模块用于管理患者的档案信息、病历信息以及病历预约信息等。 医生管理模块 医生管理模块用于管理医生的信息、排班信息以及医生的病历信息等。 药品管理模块 药品管理模块用于管理医院的药品信息、出库信息以…

    Java 2023年5月23日
    00
  • SpringSecurity自定义登录成功处理

    Spring Security是一个基于Spring框架的安全框架,它提供了一系列的安全服务,包括身份验证、授权、攻击防护等。在Spring Security中,我们可以自定义登录成功处理来实现自定义的登录成功逻辑。在本文中,我们将详细讲解Spring Security自定义登录成功处理的完整攻略。 自定义登录成功处理 在Spring Security中,我…

    Java 2023年5月18日
    00
  • Mac OS上安装Tomcat服务器的简单步骤

    下面我将为您详细介绍在Mac OS上安装Tomcat服务器的简单步骤。 1. 下载Tomcat 首先,在Apache Tomcat官网(http://tomcat.apache.org)下载Tomcat的二进制发行版。选择最新版本,下载Core的tar.gz版,解压到一个合适位置。 2. 配置环境变量 打开终端,输入以下命令添加环境变量: $ vim ~/.…

    Java 2023年5月19日
    00
  • Spring+MongoDB实现登录注册功能

    下面就为你讲解如何使用Spring和MongoDB实现登录注册功能。 准备工作 安装并启动MongoDB服务器 创建Maven项目,引入所需依赖 xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boo…

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