MyBatis订单与用户映射实现笔记

📅 发布时间:2026/7/10 19:34:14 👁️ 浏览次数:
MyBatis订单与用户映射实现笔记
一、前言在 MyBatis 开发中关联查询是处理多表数据的核心场景而「一对一」关联是最基础的关联关系模型。本文以订单Order与用户User为例详细讲解一对一关联查询的两种通用实现方案SQL99 连表查询、分布式分段查询并结合企业开发最佳实践说明「联表查询 大实体类」的主流用法。这些方案不仅适用于一对一关系也可无缝迁移至一对多、多对多关联场景。二、前置准备数据库与环境2.1 数据库表设计先创建用户表和订单表订单表通过user_id关联用户表主键业务场景限定为「单个订单仅关联一个用户」一对一-- 用户表 CREATE TABLE user ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 用户ID, username VARCHAR(50) NOT NULL COMMENT 用户名, phone VARCHAR(20) DEFAULT NULL COMMENT 手机号, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; -- 订单表 CREATE TABLE order ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 订单ID, order_no VARCHAR(30) NOT NULL COMMENT 订单编号, amount DECIMAL(10,2) NOT NULL COMMENT 订单金额, user_id BIGINT NOT NULL COMMENT 关联用户ID, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), KEY idx_user_id (user_id), CONSTRAINT fk_order_user FOREIGN KEY (user_id) REFERENCES user (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;2.2 环境依赖Maven核心依赖仅需 MyBatis 和 MySQL 驱动示例如下dependencies !-- MyBatis核心依赖 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.13/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version scoperuntime/scope /dependency !-- 测试依赖 -- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.13.2/version scopetest/scope /dependency /dependencies三、核心步骤 1创建实体类3.1 基础实体类User Order通过在Order类中嵌入User对象确立「订单 - 用户」的一对一关联关系// 用户实体类 public class User { private Long id; // 用户ID private String username; // 用户名 private String phone; // 手机号 private Date createTime; // 创建时间 // 省略getter/setter/toString方法 } // 订单实体类包含User对象体现一对一 public class Order { private Long id; // 订单ID private String orderNo; // 订单编号 private BigDecimal amount; // 订单金额 private Long userId; // 关联用户ID private Date createTime; // 创建时间 private User user; // 一对一关联订单所属用户 // 省略getter/setter/toString方法 }3.2 大实体类OrderUserVO企业常用封装联表查询的全部结果无需嵌套对象适配ResultType直接接收// 订单用户联表查询结果VO大实体类 public class OrderUserVO { private Long orderId; // 订单ID private String orderNo; // 订单编号 private BigDecimal amount; // 订单金额 private Long userId; // 用户ID private String username; // 用户名 private String phone; // 用户手机号 // 省略getter/setter/toString方法 }四、实现方案 1SQL99 标准连表查询SQL99 是主流的连表语法JOIN直接一次查询获取关联数据性能更优。4.1 方式 1ResultType 大实体类企业最常用4.1.1 Mapper 接口public interface OrderMapper { /** * 连表查询订单用户信息ResultType接收 * param orderId 订单ID * return 订单用户组合VO */ OrderUserVO selectOrderUserByOrderId(Long orderId); }4.1.2 Mapper.xml 映射文件?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.mapper.OrderMapper !-- ResultType方式直接映射到大实体类 -- select idselectOrderUserByOrderId resultTypecom.example.vo.OrderUserVO SELECT o.id AS orderId, o.order_no AS orderNo, o.amount AS amount, u.id AS userId, u.username AS username, u.phone AS phone FROM order o INNER JOIN user u ON o.user_id u.id WHERE o.id #{orderId} /select /mapper4.2 方式 2ResultMap 嵌套实体精准映射适用于需要返回嵌套User对象的场景无需创建 VO4.2.1 Mapper 接口public interface OrderMapper { /** * 连表查询订单用户信息ResultMap嵌套映射 * param orderId 订单ID * return 包含User对象的Order */ Order selectOrderWithUserByOrderId(Long orderId); }4.2.2 Mapper.xml 映射文件!-- ResultMap方式嵌套映射User对象 -- resultMap idOrderUserResultMap typecom.example.entity.Order id columnid propertyid/ result columnorder_no propertyorderNo/ result columnamount propertyamount/ result columnuser_id propertyuserId/ result columncreate_time propertycreateTime/ !-- 一对一嵌套映射User -- association propertyuser javaTypecom.example.entity.User id columnuser_id propertyid/ result columnusername propertyusername/ result columnphone propertyphone/ result columnuser_create_time propertycreateTime/ /association /resultMap select idselectOrderWithUserByOrderId resultMapOrderUserResultMap SELECT o.id, o.order_no, o.amount, o.user_id, o.create_time, u.username, u.phone, u.create_time AS user_create_time FROM order o INNER JOIN user u ON o.user_id u.id WHERE o.id #{orderId} /select五、实现方案 2分布式分段查询核心思路分两次查询先查订单再查用户降低 SQL 耦合灵活性更高。5.1 核心步骤先查询订单基础信息根据订单中的user_id查询用户信息将用户对象注入订单对象。5.2 代码实现5.2.1 UserMapper 接口public interface UserMapper { /** * 根据用户ID查询用户 * param userId 用户ID * return 用户信息 */ User selectUserById(Long userId); }5.2.2 OrderMapper 接口 XML// OrderMapper接口 public interface OrderMapper { /** * 先查订单基础信息 * param orderId 订单ID * return 订单基础信息 */ Order selectOrderById(Long orderId); } // OrderMapper.xml select idselectOrderById resultTypecom.example.entity.Order SELECT id, order_no, amount, user_id, create_time FROM order WHERE id #{orderId} /select5.2.3 业务层组装分段查询核心public class OrderService { Autowired private OrderMapper orderMapper; Autowired private UserMapper userMapper; /** * 分段查询订单用户信息 * param orderId 订单ID * return 包含User的Order */ public Order getOrderWithUser(Long orderId) { // 第一步查订单 Order order orderMapper.selectOrderById(orderId); if (order null) { return null; } // 第二步根据userId查用户 User user userMapper.selectUserById(order.getUserId()); // 组装一对一关系 order.setUser(user); return order; } }六、总结关键点回顾一对一关联的核心在主实体Order中嵌入关联实体User对象明确关联关系两种通用查询方案SQL99 连表查询性能优、分布式分段查询灵活性高可复用至一对多 / 多对多场景结果返回方式ResultType适配大实体类常用、ResultMap适配嵌套实体按需选择。