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

总结

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

相关文章

  • springboot使用jasypt加密库实现数据库加解密示例代码

    springboot使用jasypt加密库实现数据库加解密示例代码

    这篇文章主要给大家介绍了关于springboot使用jasypt加密库实现数据库加解密的相关资料,Jasypt是一个用于配置文件加密的Java库,它可以用来加密和解密配置文件中的敏感信息,如数据库密码、API 密钥等,需要的朋友可以参考下
    2024-04-04
  • springboot实现读取nacos配置文件

    springboot实现读取nacos配置文件

    这篇文章主要介绍了springboot实现读取nacos配置文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 使用React和springboot做前后端分离项目的步骤方式

    使用React和springboot做前后端分离项目的步骤方式

    这篇文章主要介绍了使用React和springboot做前后端分离项目的步骤方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Java行为型模式中命令模式分析

    Java行为型模式中命令模式分析

    在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时可以使用命令模式来进行设计
    2023-02-02
  • SpringMVC转发与重定向参数传递的实现详解

    SpringMVC转发与重定向参数传递的实现详解

    这篇文章主要介绍了SpringMVC转发与重定向参数传递,对于重定向,可以通过FlashMap或RedirectAttributes来在请求间传递数据,因为重定向涉及两个独立的HTTP请求,而转发则在同一请求内进行,数据可以直接通过HttpServletRequest共享,需要的朋友可以参考下
    2022-07-07
  • WebSocket(java版)服务核心实例代码

    WebSocket(java版)服务核心实例代码

    WebSocket是一种协议,用于在Web应用程序和服务器之间建立实时、双向的通信连接,这篇文章主要介绍了WebSocket(java版)服务核心代码的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-12-12
  • Java使用jar命令配置服务器端口的完整指南

    Java使用jar命令配置服务器端口的完整指南

    本文将详细介绍如何使用java -jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助
    2025-08-08
  • java http token请求代码实例

    java http token请求代码实例

    这篇文章主要介绍了java http token请求,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • SpringBoot整合RabbitMQ处理死信队列和延迟队列

    SpringBoot整合RabbitMQ处理死信队列和延迟队列

    这篇文章将通过示例为大家详细介绍SpringBoot整合RabbitMQ时如何处理死信队列和延迟队列,文中的示例代码讲解详细,需要的可以参考一下
    2022-05-05
  • Java实战入门之双色球彩票小游戏

    Java实战入门之双色球彩票小游戏

    这篇文章主要介绍了Java实战入门之双色球彩票,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04

最新评论