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 实现关联。

相关推荐
刘一说7 小时前
深入解析 Spring Boot 数据访问:Spring Data JPA 与 MyBatis 集成实战
spring boot·tomcat·mybatis
赋能大师兄8 小时前
MyBatis缓存机制
mybatis·二级缓存·一级缓存
codingPower1 天前
升级mybatis-plus导致项目启动报错: net.sf.jsqlparser.statement.select.SelectBody
java·spring boot·maven·mybatis
123461612 天前
互联网大厂Java面试:从Spring Boot到微服务的探索
java·数据库·spring boot·微服务·面试·mybatis·orm
2301_801252222 天前
Mybatis的添加和修改功能
java·开发语言·mybatis
W.Buffer4 天前
MyBatis 源码深度解析:从 Spring Boot 实战到底层原理
spring boot·后端·mybatis
CS Beginner4 天前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis
m0_564264185 天前
IDEA DEBUG调试时如何获取 MyBatis-Plus 动态拼接的 SQL?
java·数据库·spring boot·sql·mybatis·debug·mybatis-plus
没有bug.的程序员5 天前
Spring Boot 整合第三方组件:Redis、MyBatis、Kafka 实战
java·spring boot·redis·后端·spring·bean·mybatis
迷了璐的航5 天前
mybatis解决查询中使用group by时出现sql_mode=only_full_group_by
数据库·sql·mybatis