MyBatis联合查询

文章目录

  • 数据库设计
  • [MyBatis 配置](#MyBatis 配置)
  • [MyBatis 映射文件](#MyBatis 映射文件)
    • [Mapper 接口](#Mapper 接口)
  • 总结

数据库设计

建表 SQL

sql 复制代码
CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL
);

CREATE TABLE `order` (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,
    order_no VARCHAR(50) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES user(id)
);

CREATE TABLE role (
    id INT PRIMARY KEY AUTO_INCREMENT,
    role_name VARCHAR(50) NOT NULL
);

CREATE TABLE user_role (
    user_id INT NOT NULL,
    role_id INT NOT NULL,
    PRIMARY KEY (user_id, role_id),
    FOREIGN KEY (user_id) REFERENCES user(id),
    FOREIGN KEY (role_id) REFERENCES role(id)
);

插入以下数据:

sql 复制代码
INSERT INTO user (name) VALUES ('Alice'), ('Bob');
INSERT INTO `order` (user_id, order_no) VALUES (1, 'ORD001'), (1, 'ORD002'), (2, 'ORD003');
INSERT INTO role (role_name) VALUES ('Admin'), ('User');
INSERT INTO user_role (user_id, role_id) VALUES (1, 1), (1, 2), (2, 2);

MyBatis 配置

我们使用 MySQL 数据库,MyBatis 的核心配置文件如下:

sql 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test_db?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

定义 Java 实体类,映射数据库表:

java 复制代码
@Data
public class User {
    private Integer id;
    private String name;
    private Order order; // 一对一:用户关联一个订单
    private List<Order> orders; // 一对多:用户关联多个订单
    private List<Role> roles; // 多对多:用户关联多个角色
}

@Data
public class Order {
    private Integer id;
    private Integer userId;
    private String orderNo;
}

@Data
public class Role {
    private Integer id;
    private String roleName;
}

MyBatis 映射文件

在 UserMapper.xml 中定义关联查询,展示一对一、一对多和多对多的实现。

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">

    <!-- 一对一 -->
    <resultMap id="UserWithOrderMap" type="com.example.entity.User">
        <id property="id" column="user_id"/>
        <result property="name" column="user_name"/>
        <association property="order" javaType="com.example.entity.Order">
            <id property="id" column="order_id"/>
            <result property="userId" column="user_id"/>
            <result property="orderNo" column="order_no"/>
        </association>
    </resultMap>
   
    <select id="selectUserWithOrder" resultMap="UserWithOrderMap">
        SELECT *
        FROM user u
        LEFT JOIN `order` o ON u.id = o.user_id
        WHERE u.id = #{id}
        LIMIT 1
    </select>

    <!-- 一对多 -->
    <resultMap id="UserWithOrdersMap" type="com.example.entity.User">
        <id property="id" column="user_id"/>
        <result property="name" column="user_name"/>
        <collection property="orders" ofType="com.example.entity.Order">
            <id property="id" column="order_id"/>
            <result property="userId" column="user_id"/>
            <result property="orderNo" column="order_no"/>
        </collection>
    </resultMap>

    <select id="selectUserWithOrders" resultMap="UserWithOrdersMap">
        SELECT *
        FROM user u
        LEFT JOIN `order` o ON u.id = o.user_id
        WHERE u.id = #{id}
    </select>

    <!-- 多对多 -->
    <resultMap id="UserWithRolesMap" type="com.example.entity.User">
        <id property="id" column="user_id"/>
        <result property="name" column="user_name"/>
        <collection property="roles" ofType="com.example.entity.Role">
            <id property="id" column="role_id"/>
            <result property="roleName" column="role_name"/>
        </collection>
    </resultMap>
    
    <select id="selectUserWithRoles" resultMap="UserWithRolesMap">
        SELECT *
        FROM user u
        LEFT JOIN user_role ur ON u.id = ur.user_id
        LEFT JOIN role r ON ur.role_id = r.id
        WHERE u.id = #{id}
    </select>
</mapper>

Mapper 接口

定义对应的 Mapper 接口:

java 复制代码
public interface UserMapper {
    User selectUserWithOrder(Integer id); // 一对一
    User selectUserWithOrders(Integer id); // 一对多
    User selectUserWithRoles(Integer id); // 多对多
}

以下是测试代码,验证查询结果:

java 复制代码
public class MyBatisTest {
    public static void main(String[] args) throws Exception {
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                .build(new FileInputStream("mybatis-config.xml"));
        try (SqlSession session = factory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);

            // 测试一对一
            User userWithOrder = mapper.selectUserWithOrder(1);
            System.out.println(userWithOrder.getName());

            // 测试一对多
            User userWithOrders = mapper.selectUserWithOrders(1);
            System.out.println(userWithOrders.getName());
            userWithOrders.getOrders().forEach(order -> System.out.println("  - " + order.getOrderNo()));

            // 测试多对多
            User userWithRoles = mapper.selectUserWithRoles(1);
            System.out.println(userWithRoles.getName());
            userWithRoles.getRoles().forEach(role -> System.out.println("  - " + role.getRoleName()));
        }
    }
}

总结

一对一:通过 association 标签,查询用户及其关联的一个订单。

一对多:通过 collection 标签,查询用户及其所有订单,MyBatis 自动将多行订单数据映射到 List。

多对多:通过 collection 标签,查询用户及其所有角色,借助中间表 user_role 实现关联。

相关推荐
CodeWolf19 小时前
个人疑惑点(一):mapper.xml 文件里的 SQL 语句在什么场景下需要用到 resultMap
mybatis
小鹅叻1 天前
MyBatis题
java·tomcat·mybatis
小猪咪piggy2 天前
【JavaEE】(18) MyBatis 进阶
java·java-ee·mybatis
计算机学姐2 天前
基于SpringBoot的老年人健康数据远程监控管理系统【2026最新】
java·vue.js·spring boot·后端·mysql·spring·mybatis
一叶飘零_sweeeet2 天前
如何避免MyBatis二级缓存中的脏读
java·redis·mybatis
chen_note3 天前
Redis数据持久化——RDB快照和Aof日志追加
java·数据库·mybatis·持久化·aof·rdb
yvya_3 天前
Mybatis总结
java·spring·mybatis
计算机学姐3 天前
基于SpringBoot的社团管理系统【2026最新】
java·vue.js·spring boot·后端·mysql·spring·mybatis
没有bug.的程序员3 天前
MyBatis 初识:框架定位与核心原理——SQL 自由掌控的艺术
java·数据库·sql·mybatis
一叶飘零_sweeeet4 天前
在分布式环境下正确使用MyBatis二级缓存
java·分布式·mybatis