Mybatis一对多查询的两种姿势(值得收藏)

前言

最近碰到了Mybatis一对多查询的场景,在这里总结对比下常见的两种实现方式。

本文以常见的订单表和订单详情表来举例说明;

数据库表准备

订单表 tbl_order

订单详情表 tlb_order_detail

ps: 一个订单关联多个订单详情,通过order_no订单号关联;

实例演示

方法一:联合查询ResultMap映射

sql直接关联查询,然后结果集通过resultMap的collection映射

例如 查询订单列表,包括订单详情

Order.java 中新增字段orderDetailList,用于存详情列表

public class Order {
    private Integer id;

    private String orderNo;

    private Date orderTime;

    private Date payTime;

    private String remark;
    /**订单详情*/
    private List<OrderDetail> orderDetailList;
    //省略get、set

OrderMapper.java 新增查询方法

    List<Order> queryOrderList(Map map);

OrderMapper.xml

<resultMap id="BaseResultMap" type="com.chouxiaozi.mybatisdruid.entity.Order" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="order_no" property="orderNo" jdbcType="VARCHAR" />
    <result column="order_time" property="orderTime" jdbcType="TIMESTAMP" />
    <result column="pay_time" property="payTime" jdbcType="TIMESTAMP" />
    <result column="remark" property="remark" jdbcType="VARCHAR" />
    <collection property="orderDetailList" ofType="com.chouxiaozi.mybatisdruid.entity.OrderDetail">
      <id column="d_id" property="id" jdbcType="INTEGER" />
      <result column="d_order_no" property="orderNo" jdbcType="VARCHAR" />
      <result column="good_name" property="goodName" jdbcType="VARCHAR" />
      <result column="good_id" property="goodId" jdbcType="INTEGER" />
      <result column="good_count" property="goodCount" jdbcType="INTEGER" />
    </collection>
  </resultMap>

<select id="queryOrderList" resultMap="BaseResultMap">
    SELECT
      o.*, d.id as d_id,d.order_no as d_order_no,d.good_name,d.good_id,d.good_count
    FROM
      tbl_order o
        LEFT JOIN tbl_order_detail d ON d.order_no = o.order_no
    where 1=1
    <if test="orderNo != null and orderNo != ''">
      and o.order_no = #{orderNo}
    </if>
    ORDER BY o.order_time desc
  </select>

查询结果展示

[
  {
    "id": 2,
    "orderNo": "DD000002",
    "orderTime": "2021-05-09 12:25:57",
    "payTime": "2021-05-09 12:25:59",
    "remark": "2号订单",
    "orderDetailList": [
      {
        "id": 5,
        "orderNo": "DD000002",
        "goodName": "耳机",
        "goodId": 5,
        "goodCount": 1
      },
      {
        "id": 4,
        "orderNo": "DD000002",
        "goodName": "手机",
        "goodId": 4,
        "goodCount": 1
      }
    ]
  },
  {
    "id": 1,
    "orderNo": "DD000001",
    "orderTime": "2021-05-09 12:25:37",
    "payTime": "2021-05-09 12:25:41",
    "remark": "1号订单",
    "orderDetailList": [
      {
        "id": 2,
        "orderNo": "DD000001",
        "goodName": "饮料",
        "goodId": 2,
        "goodCount": 2
      },
      {
        "id": 1,
        "orderNo": "DD000001",
        "goodName": "瓜子",
        "goodId": 1,
        "goodCount": 1
      },
      {
        "id": 3,
        "orderNo": "DD000001",
        "goodName": "矿泉水",
        "goodId": 3,
        "goodCount": 2
      }
    ]
  }
]

原理:sql直接关联查询,然后结果集通过resultMap的collection映射,将order_detail表对应的字段映射到orderDetailList字段中。

优点:条件查询方便;无论是订单表还是详情表如果要进行一些条件过滤的话,非常方便,直接写在where中限制就行。
不足:因为是先关联查询,后映射;如果需要进行分页查询的话,这种方式就无法满足。主表2条数据,详情表5条数据,关联之后就是10条,无法得主表进行分页;解决方法,就是先给主表套个子查询limit分页后,然后结果集再跟详情表进行关联查询;

方法二:子查询映射

通过resultMap中collection标签的select属性去执行子查询

还以查询订单列表为例

OrderMapper.java

    List<Order> queryOrderList2(Map map);

OrderMapper.xml

<!--主查询的resultMap-->
  <resultMap id="BaseResultMap2" type="com.chouxiaozi.mybatisdruid.entity.Order" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="order_no" property="orderNo" jdbcType="VARCHAR" />
    <result column="order_time" property="orderTime" jdbcType="TIMESTAMP" />
    <result column="pay_time" property="payTime" jdbcType="TIMESTAMP" />
    <result column="remark" property="remark" jdbcType="VARCHAR" />
    <!--select子查询, column 传给子查询的参数-->
    <collection property="orderDetailList" ofType="com.chouxiaozi.mybatisdruid.entity.OrderDetail"
                select="queryDetail" column="order_no">
    </collection>
  </resultMap>
  <!--主查询的sql-->
  <select id="queryOrderList2" resultMap="BaseResultMap2">
    SELECT
    o.*
    FROM
    tbl_order o
    where 1=1
    <if test="orderNo != null and orderNo != ''">
      and o.order_no = #{orderNo}
    </if>
    ORDER BY o.order_time desc
  </select>
  <!--子查询的resultMap-->
  <resultMap id="detailResuleMap" type="com.chouxiaozi.mybatisdruid.entity.OrderDetail">
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="order_no" property="orderNo" jdbcType="VARCHAR" />
    <result column="good_name" property="goodName" jdbcType="VARCHAR" />
    <result column="good_id" property="goodId" jdbcType="INTEGER" />
    <result column="good_count" property="goodCount" jdbcType="INTEGER" />
  </resultMap>
  <!--子查询的sql-->
  <select id="queryDetail" resultMap="detailResuleMap">
    SELECT
      *
    FROM
      `tbl_order_detail` where order_no = #{order_no}
  </select>

查询结果同上个例子一样;

原理:通过collection的select方法去调用子查询;所需参数通过column传递;

优点:无论是分页还是普通查询都能满足;主表增加过滤条件也很方便,直接在主查询的sql中增加where条件就行

缺点:子查询不好增加过滤条件;column只能传递主表已有的字段。下面提供解决方式;
ps:column传递多个参数 column=“{prop1=col1,prop2=col2}”

例如:实际场景中,详情表有个状态字段,只展示状态正常的详情,需要过滤详情记录。

本例子没有状态字段,就查询订单列表,详情中不展示瓜子,即详情记录中过滤掉good_id = 1的;

在上个例子基础上修改如下:

调用层传参

	Map map = new HashMap();
    map.put("goodId", 1);
    orderMapper.queryOrderList2(map);

orderMapper.xml中增加传参过滤

展示结果如下:详情中已成功过滤掉瓜子;记住,过滤子查询不会影响主表记录;

[
  {
    "id": 2,
    "orderNo": "DD000002",
    "orderTime": "2021-05-09 12:25:57",
    "payTime": "2021-05-09 12:25:59",
    "remark": "2号订单",
    "orderDetailList": [
      {
        "id": 4,
        "orderNo": "DD000002",
        "goodName": "手机",
        "goodId": 4,
        "goodCount": 1
      },
      {
        "id": 5,
        "orderNo": "DD000002",
        "goodName": "耳机",
        "goodId": 5,
        "goodCount": 1
      }
    ]
  },
  {
    "id": 1,
    "orderNo": "DD000001",
    "orderTime": "2021-05-09 12:25:37",
    "payTime": "2021-05-09 12:25:41",
    "remark": "1号订单",
    "orderDetailList": [
      {
        "id": 2,
        "orderNo": "DD000001",
        "goodName": "饮料",
        "goodId": 2,
        "goodCount": 2
      },
      {
        "id": 3,
        "orderNo": "DD000001",
        "goodName": "矿泉水",
        "goodId": 3,
        "goodCount": 2
      }
    ]
  }
]

总结

方式 联合查询映射 子查询映射
原理 sql查询完成后再通过resultmap映射结果 主表的数据集循环调用子查询
分页 不支持分页查询,主表套子查询也能实现 支持分页
条件过滤 方便条件过滤 传参也能实现,复杂参数例如list不好传递给子查询 ;子查询过滤不影响主表数据

到此这篇关于Mybatis一对多查询的文章就介绍到这了,更多相关Mybatis一对多查询内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Mybatis自关联查询一对多查询的实现示例

    注:代码已托管在GitHub上,地址是:https://github.com/Damaer/Mybatis-Learning ,项目是mybatis-13-oneself-one2many,需要自取,需要配置maven环境以及mysql环境(sql语句在resource下的test.sql中),觉得有用可以点个小星星. docsify文档地址在:https://damaer.github.io/Mybatis-Learning/#/ 所谓自关联查询,是指自己既然充当一方,又充当多方.比如新闻栏目

  • Mybatis一对多与多对一查询处理详解

    要点 主要还是结果集映射(resultMap) association标签: 一个复杂类型的关联:许多结果将包装成这种类型(JavaBean)嵌套结果映射,关联可以是 resultMap 元素,或是对其它结果映射的引用 collection标签: 一个复杂类型的集合(List)嵌套结果映射,集合可以是resultMap元素,或是对其它结果映射的引用 一对多(association) 数据库结构 tid是student的外键,是teacher表的id JavaBean public class S

  • 解决mybatis一对多关联查询多条数据只显示一条的问题

    一对多,如果多个表字段名相同,要记住使用别名,否则多条数据只显示一条 <resultMap type="com.example.demo.model.TuserModel" id="extendMapper"> <id column="id" property="id" /> <result column="user_name" property="userName&

  • MyBatis一对多嵌套查询的完整实例

    前言 嵌套查询的实现原理为两次查询,比如产品表为主表,图片表为从表通过product_id字段与产品表id字段关联实现一对多,嵌套查询 首先查询 主表的数据 然后将主表id字段赋值给从表实体类中product_id 字段(productId)然后通过dao接口路径映射找到对应的MyBatis XMl文件SQL语句ID如:com.liao.dao.DImgMapper.selectDImgByProductId 进行子查询也就是第二次查询.然后返回数据 数据库建表语句和测试数据如下: 数据库版本为

  • 解决mybatis plus 一对多分页查询问题

    最近用mybatis plus做项目,单表的增删改查都正常,做到 1对多表的分页时,用resultMap返回的时候发现返回的记录和总数对不上 返回的记录是 一 表的,二返回的总数是 多 表 查了一下,这个或者是PLUS的bug 大概的解决办法如下图:用collection,传参用column,我这里用了一个小技巧, 把外面传入的参数,作为主表的column传入到从表. 这里没找到其他方法,有其他方法可以评论告诉我 补充知识:解决Mybatis-plus利用collection查询一对多分页数据的

  • Mybatis 一对多和多对一关联查询问题

    首先  数据库量表之间字段关系(没有主外键) studentmajor表的id字段对应student表里major字段 两个实体类 package com.model; import java.util.Date; public class Student { private Integer sno; private String sname; private String ssex; private Integer sclass; private StudentMajor studentmaj

  • mybatis一对多查询功能

    首先,我们还是先给出一个需求:根据订单id查询订单明细--我们知道,一个订单里面可以有多个订单的明细(需求不明确的同学,请留言或者去淘宝网上的订单处点一下就知道了).这个时候,一个订单,对应多个订单的id.这种需求出现的时候,我们应该如何查询呢? 此时我们的数据模型如下图(左)由于查询用户也是我们的需求,所以就在原有的基础上进行扩展,数据模型如下(右): 很显然,如果用resultType的方式去实现的话,是不合理的了.因为我们需要创建一个既有订单又有订单明细的pojo然后呢,我们的mybati

  • mybatis高级映射一对多查询实现代码

    1.需求分析: 在开发中会遇到这样一个问题,查询订单信息,级联查询出用户信息和订单明细信息 2.sql语句实现 2.1确定主查询表:订单表 2.2确定关联查询表:用户表, 订单明细表 sql语句如下: select orders.*, t_user.address, t_user.name, t_user.brithday, orderdetail.id orderdetail_id, orderdetail.orderid, orderdetail.itemsid from orders, t

  • mybatis 一对一、一对多和多对多查询实例代码

    关键字:association 一对一映射(一个班级只有一个班主任) <select id="getClass" parameterType="int" resultMap="ClassesResultMap"> select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id} </select> <resultMap type=&q

  • Mybatis关联查询之一对多和多对一XML配置详解

    平时在开发过程中dao.bean和XML文件都是自动生成的,很少写XML的配置关系,今天记录一下mybatis的关联查询中的多对一和一对多的情况. 首先是有两张表(学生表Student和老师Teacher表,注:这里只是为了演示一对多和多对一的情况,请不要杠),为了更易懂,这里只设置了最简单的几个必要字段.表结构如下图 Student表: Teacher表: 创建实体bean Teacher.java: import java.util.List; public class Teacher {

随机推荐