我是靠谱客的博主 甜美小蝴蝶,最近开发中收集的这篇文章主要介绍8. MyBatis嵌套查询 - 一对一 - 一对多8. MyBatis嵌套查询 - 一对一 - 一对多,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

8. MyBatis嵌套查询 - 一对一 - 一对多

前言

在上一篇中我们已经基本认识了 MyBatis 的多表查询了。那么 MyBatis 还有一个比较有意思的功能,就是 嵌套查询。 这个功能有些类似 SQL 的多表联合查询,但是又不是。下面我们来认识一下。

什么是嵌套查询

嵌套查询就是将原来多表的联合查询语句拆成 多个单表的查询,再使用mybatis的语法嵌套在一起。

举个栗子

* 需求:查询一个订单,与此同时查询出该订单所属的用户

* 1. SQL 关联查询:
  select * from orders o inner join user u on o.uid = u.id where o.id = 1;
  
    * 缺点:
            sql语句编写难度大
            如果表中数据量大,笛卡尔积数量倍增,可能造成内存溢出
  
* 2. MyBatis 嵌套查询:
 a.根据订单id查询订单表
  select * from orders where id = 1; 
  // 查到订单id=1的订单信息 (uid=41)
  // 结果映射到 orders对象中
 b.再根据订单表中uid(外键)查询用户表
  select * from user where id = 订单表uid;
  // 结果映射到 orders.user 中
 c.最后由mybatis框架进行嵌套组合
  
  跟子查询的区别
   1. 嵌套查询分别执行两句sql : 又有订单信息,又有对应的用户信息
   2. 子查询执行一句 : 只能查到 订单编号为1的所属的用户信息
    select * from user where id = (select uid from orders where id = 1) 
    * 优点:
            sql语句编写简单
            没有多表关联,不会产生笛卡尔积, 特别是在表数据比较多的情况, 更有优势

看了上面的说明之后,下面来写写具体案例。

一对一【嵌套查询】

需求

需求:查询一个订单,与此同时查询出该订单所属的用户

sql语句

-- 1.根据订单id查询订单表
 select * from orders where id = 1;
-- 2.再根据订单表中uid(外键)查询用户表
 select * from user where id = 41;

执行过程:

image-20210319161119939

下面我们来看看具体实现代码。

案例实现

1. 编写OrderMapper接口:编写查询 Orders 的接口方法 findOrderByIdWithUser

image-20210322225408364
public interface OrdersMapper {

    /*
      一对一关系
        # 查询id=?的订单以及对应的用户
             select * from orders o inner join user u
               on o.uid = u.id
                   where o.id = ?;

            1. 参数类型: Integer id
            2. 返回值类型  Orders

        # 修改成嵌套查询
            1. 先查订单id=1 的订单信息  (uid=41)
                select * from orders where id = ? // 订单id
            2. 查uid=41的用户信息
                select * from user where id = ?  // 用户id

            3. 两个结果嵌套一起: 映射到 orders
    * */
    Orders findOrderByIdWithUser(Integer id);

}

2. 编写OrderMapper映射:映射 findOrderByIdWithUser 查询方法

image-20210322235049225
<?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.lijw.dao.OrdersMapper">

    <!--
        设置查询结果集 resultMap, 结果映射为 Orders 类
    -->
    <resultMap id="myorder" type="Orders" autoMapping="true">
        <!--  设置 id 字段映射 Orders 类的属性 id -->
        <id property="id" column="id"/>
        <!--  设置普通字段 ordertime 映射 Orders 类的属性 ordertime   -->
        <result property="ordertime" column="ordertime"/>
        <!--
            # 嵌套查询重点:
                0. 目的
                    select * from user where id = ?
                        映射到 orders.user属性中
                1. 编写查询user表的语句:
                    UserMapper.findUserById -> UserMapper.xml
                2. 嵌套到这里
                    association标签的两个属性
                        a. column : 条件 (执行查询方法的参数)
                         b. select : 调用第二句sql执行
                            接口的权限定名.方法名
                            UserMapper.findUserById(用户id)
        -->
        <association property="user" javaType="user" autoMapping="true"
                     column="uid"
                     select="com.lijw.dao.UserMapper.findUserById">
            <id property="id" column="uid"/>
            <result property="username" column="username"/>
        </association>
    </resultMap>

    <select id="findOrderByIdWithUser" resultMap="myorder">
        select * from orders where id = #{id}
    </select>
    
</mapper>

3. 编写 UserMapper接口:设置根据 id 查询 user 表的方法

image-20210322235234278
public interface UserMapper {

    /*
    *  select * from user where id = ?
    *  1. 参数: Integer id 用户标号
    *  2. 返回值: User
    * */
    User findUserById(Integer id);
}

4. UserMapper映射:编写映射 SQL

image-20210322235425456
<?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">
<!--
实体类的映射文件
namespace 指定接口的类全名
-->
<mapper namespace="com.lijw.dao.UserMapper">

    <select id="findUserById" resultType="user">
        select * from user where id = #{id}
    </select>
</mapper>

5. 通过mybatis进行嵌套组合

看 OrderMapper.xml里的嵌套设置

image-20210322235517865

一对一在结果映射 resultMap 中使用 association 进行嵌套查询,column 为传递的从 Orders 数据中查询出来的 uid.

6. 测试

image-20210322235807355
public class OrderMapperTest{ 
    @Test
    public void test02(){
        SqlSession session = MyBatisUtil.getSqlSession();

        OrdersMapper mapper = session.getMapper(OrdersMapper.class);
        // 订单编号 = 1
        Orders orders = mapper.findOrderByIdWithUser(1);
        System.out.println("订单:" + orders);

        MyBatisUtil.commitAndClose(session);
    }
}

一对多【嵌套查询】

需求

需求:查询一个用户,与此同时查询出该用户具有的订单

sql语句

-- 1. 先根据用户id,查询用户表(一个)
SELECT * FROM `user` WHERE id = 41;
-- 2. 再根据用户id,查询订单表(多个)
SELECT * FROM orders WHERE uid = 41;

执行如下:

image-20210323000047357

image-20210323000108845

案例实现

1. OrderMapper接口:编写根据 id 查询该用户 User 下的订单 Orders 的方法

image-20210323000433262
public interface OrderMapper {

    /** 
     * # 查询id=? 的用户以及拥有的订单
     * select * from user u inner join orders o
             on u.id = o.uid
                 where u.id = ?;
     * 1. 参数类型: Integer
     * 2. 返回值类型: User
     * <p>
     * # 修改成嵌套查询
     * a. 查询用户id=? 的用户
     * select * from user where user.id = ?;
     * <p>
     * b. 查询该用户的订单信息
     * select * from orders where uid = ?;
     * <p>
     * c. 嵌套
     */
    User findUserByIdWithOrders(Integer uid);
    
}

2. OrderMapper映射:编写映射 SQL

image-20210323001118623
    <!--  根据id查询订单Orders的用户信息  -->
    <resultMap id="myuser" type="user" autoMapping="true">
        <id property="id" column="id"/>
        <!--
            collection: 为一对多的查询存储方式
                查询对应的订单信息  ->  user.list中
                column : 条件(结果集字段作为查询语句的参数)
        -->
        <collection property="list" ofType="orders" autoMapping="true"
                    column="id"
                    select="com.lijw.dao.OrdersMapper.findOrdersByUid">
            <id property="id" column="oid"/>
        </collection>
    </resultMap>

    <select id="findUserByIdWithOrders" resultMap="myuser">
        select * from user where user.id = #{uid}
    </select>

3. 编写第二句sql的接口和映射文件

image-20210323001321222
 public interface OrderMapper {
 /*
    *  select * from orders where uid = ?;
    *
    *  参数类型: Integer id
    *  返回值类型: List<Orders>
    * */
    List<Orders> findOrdersByUid(Integer uid);
 }     
   

image-20210323001422855
    <!--  根据uid查询订单信息  -->
    <select id="findOrdersByUid" resultType="orders">
        select * from orders where uid = #{uid}
    </select>

4. 通过mybatis进行嵌套组合

查看OrderMapper.xml文件

image-20210323001550819

5. 测试

image-20210323001730840
public class UserMapperTest extends BaseMapperTest {

    // 一对多嵌套查询测试
    @Test
    public void test03(){
        SqlSession session = MyBatisUtil.getSqlSession();

        OrdersMapper mapper = session.getMapper(OrdersMapper.class);
        // 查询用户id=41的用户以及拥有的订单
        User user = mapper.findUserByIdWithOrders(41);
        System.out.println(user);

        MyBatisUtil.commitAndClose(session);
    }

}

1589249880000

小结

* 步骤:一对多举例
 1)先查询(一方)单表
 2)再查询(多方)单表
 3)最后由mybatis嵌套组合

一对一配置:使用<resultMap>+<association>做配置,通过column条件,执行select查询

一对多配置:使用<resultMap>+<collection>做配置,通过column条件,执行select查询

优点:1.简化sql语句编写、2.不会产生笛卡尔积

缺点: 执行两遍

开发中到底使用哪一种?
 传统开发,数据量小:使用联合查询(执行一次,传输一次)
 互联网开发,数据量大:使用嵌套查询 (执行两次,但是只需要传输一次)
  当前也有人这么玩(知道): 
   在java中先查用户,在查角色,不在使用嵌套....(执行两次,需要传输两次)

最后

以上就是甜美小蝴蝶为你收集整理的8. MyBatis嵌套查询 - 一对一 - 一对多8. MyBatis嵌套查询 - 一对一 - 一对多的全部内容,希望文章能够帮你解决8. MyBatis嵌套查询 - 一对一 - 一对多8. MyBatis嵌套查询 - 一对一 - 一对多所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部