SQL子查询与MyBatis映射过程

 更新时间:2026年04月21日 16:03:42   作者:二哈喇子!  
本文介绍了使用SQL别名、MyBatis字段映射及代码复用优化SQL片段的完整案例,通过子查询将统计逻辑封装化,减少数据库交互次数,提高性能,字段映射确保数据库字段与Java属性一致,处理命名差异,SQL代码复用统一管理公共字段,只需一处修改

前言

以下是一个结合 SQL 别名、子查询、MyBatis 字段映射和代码复用的完整案例,以用户管理系统为例:

场景描述

查询用户信息时需同时显示:

  • 基础用户信息
  • 所属部门名称
  • 最近3个月的订单数量
  • 使用代码复用优化重复SQL片段

1. 数据库表结构

用户表(User)

1. 数据库表结构

部门表(Department)

1. 数据库表结构_图2

订单表(Order)

1. 数据库表结构_图3

2. MyBatis Mapper XML

<!-- 结果映射 -->
<mapper namespace="com.example.dao.UserMapper">
	<resultMap id="userResultMap" type="实体类的全限定名">
	  <result property="userId" column="USER_ID"/>
	  <result property="username" column="USER_NAME"/>
	  <result property="departmentName" column="DEPARTMENT_NAME"/>
	  <result property="orderCount" column="ORDER_COUNT"/>
	  <result property="createTime" column="CREATE_TIME"/>
	</resultMap>
</mapper>
<!-- 定义可复用的基础字段 -->
<sql id="baseUserColumns">
  u.id AS USER_ID,
  u.username AS USER_NAME,
  u.create_time AS CREATE_TIME
</sql>
<!-- 定义部门关联字段 -->
<sql id="deptColumns">
  d.dept_name AS DEPARTMENT_NAME
</sql>
<!-- 复合查询 -->
<select id="selectUserWithStats" resultMap="userResultMap">
  SELECT 
    <!-- 复用基础字段 -->
    <include refid="baseUserColumns"/>,
    <!-- 复用部门字段 -->
    <include refid="deptColumns"/>,
    <!-- 使用子查询和别名 -->
    (
      SELECT COUNT(*) 
      FROM `order` o 
      WHERE o.user_id = u.id
      AND o.order_time >= DATE_SUB(NOW(), INTERVAL 3 MONTH)
    ) AS ORDER_COUNT
  FROM user u
  LEFT JOIN department d ON u.dept_id = d.id
  WHERE u.id = #{userId}
</select>

3. Java 实体类

public class UserDTO {
    private Long userId;               // 映射 USER_ID
    private String username;           // 映射 USER_NAME
    private String departmentName;     // 映射 DEPARTMENT_NAME
    private Integer orderCount;        // 映射 ORDER_COUNT
    private Date createTime;           // 映射 CREATE_TIME

    // Getters and Setters
}

4. 技术点解析

子查询封装

(SELECT COUNT(*) ...) AS ORDER_COUNT
  • 将复杂统计逻辑封装在子查询中:这种方法可以使得主查询更加简洁,同时将复杂的业务逻辑(例如统计订单数量)隔离在一个子查询内,便于维护。
  • 避免多次查询数据库:通过一次性获取所有所需的数据(包括通过子查询计算得到的数据),减少了与数据库交互的次数,提高了性能。

MyBatis字段映射

<resultMap id="userResultMap" type="UserDTO">
  <id property="userId" column="USER_ID"/>
  <result property="departmentName" column="DEPARTMENT_NAME"/>
</resultMap>
  • 实现数据库字段到对象属性的映射resultMap用于定义如何将数据库查询结果映射到Java对象的属性上。
  • 处理命名差异问题:通过明确指定columnproperty,解决了数据库字段命名与Java属性命名不一致的问题,同时也考虑了大小写的差异。

SQL代码复用

<include refid="baseUserColumns"/>
<include refid="deptColumns"/> 
  • 统一管理公共字段:使用<sql>标签定义可复用的SQL片段,可以在不同的查询中引用这些片段,增强了代码的一致性和可维护性。
  • 修改时只需改动一处:如果基础字段发生变化,只需要在定义的SQL片段中进行一次修改,而不需要在每一个引用该片段的地方分别更新。

这样整理后的内容更清晰地反映了每个技术点的作用及其重要性,并提供了关于如何正确实现这些功能的具体指导。

5. 执行效果

当调用selectUserWithStats方法查询用户ID时:

  • 目标:获取某个特定用户的基本信息及其最近3个月的订单活动情况。

生成的SQL

在AS后面,不可以直接写字段名,一定要通过数据库字段(column) → 映射到 → Java 对象属性(property)

比如:

生成的SQL

SELECT 
  U.ID AS USER_ID,
  U.USERNAME AS USER_NAME,
  U.CREATE_TIME AS CREATE_TIME,
  D.DEPT_NAME AS DEPARTMENT_NAME,
  (SELECT COUNT(*) 
   FROM `order` O 
   WHERE O.USER_ID = U.ID
   AND O.ORDER_TIME >= DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH)) AS ORDER_COUNT
FROM USER U
LEFT JOIN DEPARTMENT D ON U.DEPT_ID = D.ID
WHERE U.ID = #{userId}

注意事项:

  • 使用了反引号(``)包裹order表名,因为order是SQL关键字。
  • 使用CURRENT_DATE()函数代替NOW()来确保只考虑日期部分(如果时间部分不重要)。
  • 确保别名使用大写,与之前定义的resultMap中的column属性匹配。

SQL子查询解释

(SELECT COUNT(*) 
 FROM `order` o 
 WHERE o.user_id = u.id
 AND o.order_time >= DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH)) AS ORDER_COUNT
  • 作用:计算特定用户在过去3个月内生成的订单数量。
  • 逻辑:从order表(别名为o)中计数所有满足条件的记录:user_id与外部查询中的用户ID相匹配,且order_time在当前日期起往前推3个月的时间范围内。结果被命名为ORDER_COUNT

查询结果映射

UserDTO{
  userId=1001, 
  username="张三", 
  departmentName="技术部", 
  orderCount=5, 
  createTime=2023-01-15 // 假设时间为2023年1月15日
}
  • 说明:此映射显示了如何将查询结果转换为Java对象。每个数据库字段通过MyBatis的resultMap配置正确映射到相应的Java属性上,确保数据类型和命名的一致性。

6. 注意

在MyBatis的<result>标签中,column属性用于指定数据库表中的列名,而property属性则指定了对应的Java对象中的属性名。具体来说:

标签的作用

  • <result>:用于映射简单数据类型的结果集列到Java对象的属性上。它通常用于非主键字段的映射。

column属性

  • 含义:表示数据库查询结果集中列的名称。这个名称必须与SQL查询返回的列名(包括别名)完全一致。
  • 用途:告诉MyBatis从哪个列中获取数据,并将其映射到Java对象的指定属性上。

property 属性

这个属性指定了Java对象中的属性名。MyBatis会将查询结果集中对应列(通过column指定)的值赋给这个属性

  • 数据库中的表(Table)会被映射为类(Class)。
  • 表中的列(Column)会被映射为类的属性(Field/Property)。
  • 表中的行(Row)会被映射为类的实例(Object)。

如果在MyBatis Mapper XML中遇到两个一样的column,比如说实体中先来了一个name字段,又来了一个newName字段, column属性都取名叫 NAME ,这不对,要给后来的newName字段取一个新名字

例:NEW_NAME

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java队列实现方法(顺序队列,链式队列,循环队列)

    java队列实现方法(顺序队列,链式队列,循环队列)

    下面小编就为大家分享一篇java队列实现方法(顺序队列,链式队列,循环队列),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • Java concurrency集合之 CopyOnWriteArrayList_动力节点Java学院整理

    Java concurrency集合之 CopyOnWriteArrayList_动力节点Java学院整理

    这篇文章主要介绍了Java concurrency集合之 CopyOnWriteArrayList的相关资料,需要的朋友可以参考下
    2017-06-06
  • Docker环境下Spring Boot应用内存飙升分析与解决场景分析

    Docker环境下Spring Boot应用内存飙升分析与解决场景分析

    当运行一个Spring Boot项目时,如果未设置JVM内存参数,Spring Boot默认会采用JVM自身默认的配置策略,接下来通过本文给大家介绍Docker环境下Spring Boot应用内存飙升分析与解决方法,需要的朋友参考下吧
    2021-08-08
  • java中@EnableAutoConfiguration注解使用

    java中@EnableAutoConfiguration注解使用

    在Spring Boot框架中,@EnableAutoConfiguration是一种非常重要的注解,本文就来介绍一下java中@EnableAutoConfiguration注解使用,感兴趣的可以了解一下
    2023-11-11
  • Java Mybatis框架由浅入深全解析中篇

    Java Mybatis框架由浅入深全解析中篇

    MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码本文将为大家深入的介绍一下MyBatis的使用
    2022-07-07
  • JVM入门之JVM内存结构内容详解

    JVM入门之JVM内存结构内容详解

    这篇文章主要介绍了JVM入门之JVM内存结构内容详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • response.sendRedirect()实现重定向(页面跳转)

    response.sendRedirect()实现重定向(页面跳转)

    在Java web开发中,使用response.sendRedirect()可实现重定向功能。本文将介绍如何使用该方法进行页面跳转,以及该方法的使用场景和注意事项,感兴趣的可以了解一下
    2023-04-04
  • springboot乱码问题排查思路解析

    springboot乱码问题排查思路解析

    这篇文章主要为大家介绍了springboot乱码问题排查思路解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • Springboot之@ConfigurationProperties注解解读

    Springboot之@ConfigurationProperties注解解读

    在Spring Boot中,@EnableConfigurationProperties注解的主要作用是激活@ConfigurationProperties注解的配置属性类,从而让配置属性类能被Spring容器管理,这样的话,我们就可以在属性类中轻松地使用@ConfigurationProperties来绑定配置文件中的属性
    2024-10-10
  • spring aop pointcut 添加多个execution方式

    spring aop pointcut 添加多个execution方式

    这篇文章主要介绍了spring aop pointcut 添加多个execution方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11

最新评论