站在巨人的肩膀上
 
 http://crocutax.com/blog/mybatis-one-to-many-nestes-query-and-page-query

Mybatis一对多嵌套查询和分页

需求:根据分类ID查询分类下所属的商品集合,每个商品又有一个图片集合。

类似的需求有很多,比如经典的一个用户有N个角色,一个角色有N个权限,那么通过用户的id来查询角色和权限数据等等。

至于分页插件,无论是Mybatis-PageHelper还是Mybatis-Plus都可以辅助,这里主要记录不同查询方式对分页的影响。

先展示结果:

Copy{
"code": 0,
"msg": "success",
"data": {
"total": 9,
"size": 2,
"pages": 5,
"current": 1,
"records": [
{
"id": 1,
"code": "1410854032",
"name": "Esmeralda Kilback",
"categoryId": "1",
"originPrice": 359,
"price": 103,
"sales": 299,
"commentCount": 0,
"freight": 1,
"detail": "这里是商品详情",
"createdAt": "2018-04-09 18:52:05",
"updatedAt": "2018-04-24 23:41:49",
"images": [
{
"id": 40,
"productId": "1",
"link": "uploads/product/201804/18/78a6e4e4d73bfc64b7aef88a90e7f192.png",
"createdAt": "2018-04-09 18:52:05",
"updatedAt": "2018-04-18 16:37:09"
},
{
"id": 41,
"productId": "1",
"link": "uploads/product/201804/18/fffdccaa36a8475ed3d2c71c2f43cb86.png",
"createdAt": "2018-04-09 18:52:05",
"updatedAt": "2018-04-18 16:37:09"
},
{
"id": 301,
"productId": "1",
"link": "uploads/product/201804/18/68b18cbcb090a94123abd9d729528370.png",
"createdAt": "2018-04-18 16:35:56",
"updatedAt": "2018-04-18 16:35:56"
}
]
},
{
"id": 8,
"code": "1925117917",
"name": "Edgardo Osinski",
"categoryId": "1",
"originPrice": 389,
"price": 154,
"sales": 199,
"commentCount": 0,
"freight": 14,
"detail": "这里是商品详情...5052 Kyler Walk Suite 921",
"createdAt": "2018-04-09 18:52:05",
"updatedAt": "2018-04-09 18:52:05",
"images": [
{
"id": 58,
"productId": "8",
"link": "uploads/default.png",
"createdAt": "2018-04-09 18:52:05",
"updatedAt": "2018-04-09 18:52:05"
},
{
"id": 59,
"productId": "8",
"link": "uploads/default2.png",
"createdAt": "2018-04-09 18:52:05",
"updatedAt": "2018-04-09 18:52:05"
},
{
"id": 60,
"productId": "8",
"link": "uploads/default3.png",
"createdAt": "2018-04-09 18:52:05",
"updatedAt": "2018-04-09 18:52:05"
}
]
}
]
}
}

定义模型

Product用于数据库映射,为了保持其简洁,其他的二次封装不在Product里进行,而用继承的方式。

定义模型ProductVo

Copy@Data
public class ProductVo extends Product { private List<ProductImage> images;
}

方式1:结果查询

  1. 在ProductsMapper.xml中定义select语句,一次性将关联数据全部查询出来,然后进行结果映射
Copy    <select id="selectProductsBycategoryId"  resultMap="productsListMap">
select
p.id,
p.name,
p.code,
...
i.id images_id,
i.product_id images_product_id,
...
from products p
inner join product_images i on p.id = i.product_id
where p.category_id = #{id}
</select>
  1. 定义productsListMap结果映射
Copy    <resultMap id="productsListMap" type="com.longke.mallb2c.entity.vo.ProductVo" extends="BaseResultMap">-->
<collection property="images" columnPrefix="images_" resultMap="com.longke.mallb2c.mapper.ProductImagesMapper.BaseResultMap"/>
</resultMap>

注意:

  • property就是在ProductVo中定义的商品图片集合images字段
  • 用到了columnPrefix列前缀,只是别名前缀,跟数据库内的字段无关,这个images_别名前缀跟select中定义别名时要保持一致。
  • 用到了extends继承已有的BaseResultMap,不用在这里再重新写Product表的每个字段的映射了。mapper.xml自动生成工具都会帮我们生成这个BaseResultMap,直接继承即可。
  • collection用于一对多查询,查询的结果映射直接复用ProductImagesMapper中定义的BaseResultMap

总结

优点

  • 一次性查询,集中映射,简单,效率

缺点

  • 会将collection中查询到的条数作为分页的约束条件,导致分页数据不准确。

比如想查page=1,limit=10的数据,本来期望的是查询出10个商品,然后这10个商品分别再嵌套查询出自己的商品图片集合。但是会发现,可能商品只有两三个,每个下面都带了自己的商品图片集合。

原因:

先通过表连接把表记录关联进来了,如果有3个商品,关联图片表之后每个商品有4条图片记录,那么其实这时候虽然只有三个商品,但是这个内存中的临时表已经有12条记录了,在语句的最后加上 limit 0,10,其实分页的时候分的是这12条记录。最终就会导致最终的映射结果只出现了3个商品,而非我们期望的10个商品。

方式2:嵌套查询

  1. 在ProductsMapper.xml中定义select语句
Copy   <select id="selectProductsBycategoryId"  resultMap="productsListMap">
select <include refid="Base_Column_List"/>
from products
where category_id = #{id}
</select>
  1. 定义productsListMap结果映射
Copy    <resultMap id="productsListMap" type="com.longke.mallb2c.entity.vo.ProductVo" extends="BaseResultMap">
<collection property="images" ofType="com.longke.mallb2c.entity.ProductImage"
column="{productId=id}" select="com.longke.mallb2c.mapper.ProductImagesMapper.selectByProductId">
</collection>
</resultMap>

注意:

  • column是参数传递,即将Product的哪个属性传递给嵌套的查询语句,{productId=id}代表将Product的id属性传递给参数productId
  • select直接使用ProductImagesMapper中定义的select语句
  1. ProductImagesMapper定义selectByProductId查询语句
Copy    <select id="selectByProductId" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/>
from product_images
where product_id = #{productId}
</select>

总结

优点

  • 准确分页

缺点

  • 没有解决N+1的问题,多条SQL查询语句,效率太差

Mybatis分页中遇到的坑2的更多相关文章

  1. Mybatis分页中遇到的坑3

    Mybatis Mapper.xml 配置文件中 resultMap 节点的源码解析   相关文章 Mybatis 解析配置文件的源码解析 Mybatis 类型转换源码分析 Mybatis 数据源和数 ...

  2. Mysql系列八:Mycat和Sharding-jdbc的区别、Mycat分片join、Mycat分页中的坑、Mycat注解、Catlet使用

    一.Mycat和Sharding-jdbc的区别 1)mycat是一个中间件的第三方应用,sharding-jdbc是一个jar包 2)使用mycat时不需要改代码,而使用sharding-jdbc时 ...

  3. Mybatis分页和Spring的集成

    写了一个Mybatis分页控件,在这记录一下使用方式. 在Maven中加入依赖: ? 1 2 3 4 5 6 7 8 9 <dependencies>   ...     <depe ...

  4. mybatis分页插件以及懒加载

    1.   延迟加载 延迟加载的意义在于,虽然是关联查询,但不是及时将关联的数据查询出来,而且在需要的时候进行查询. 开启延迟加载: <setting name="lazyLoading ...

  5. Mybatis分页插件PageHelper正确的用法(网上有2篇不够科学的文章)

    今天下午在Mybatis项目中.实现分页.由于我是后加入项目中的,Leader用的是PageHelper这个组件.可是我在实际使用的过程中遇到了2个大问题. 1.p=2#comments" ...

  6. Mybatis分页插件PageHelper正确的使用方法(网上有2篇不够科学的文章)

    今天下午在Mybatis项目中,实现分页.因为我是后加入项目中的,Leader用的是PageHelper这个组件,但是我在实际使用的过程中遇到了2个大问题. 1.http://www.oschina. ...

  7. Mybatis分页插件PageHelper的配置和使用方法

     Mybatis分页插件PageHelper的配置和使用方法 前言 在web开发过程中涉及到表格时,例如dataTable,就会产生分页的需求,通常我们将分页方式分为两种:前端分页和后端分页. 前端分 ...

  8. Mybatis分页插件PageHelper使用

    一. Mybatis分页插件PageHelper使用  1.不使用插件如何分页: 使用mybatis实现: 1)接口: List<Student> selectStudent(Map< ...

  9. mybatis分页练手

    最近碰到个需求,要做个透明的mybatis分页功能,描述如下:目标:搜索列表的Controller action要和原先保持一样,并且返回的json需要有分页信息,如: @ResponseBody @ ...

随机推荐

  1. Debug 和 Release 的区别

    Debug 和 Release 的区别         Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序.Release 称为发布版本,它往往是进行了各种优化,使得程 ...

  2. 函数----Function对象

    函数---Function对象 一 .  函数的书写 函数 : 就是将一些语句进行封装,然后通过调用的形式,执行这些语句. 函数的作用 : ● 将大量重复的语句写在函数里,以后需要这些语句的时候,可以 ...

  3. Double.valueOf()与Double.parseDouble()两者的区别

    写代码用到这两个方法,不知道有什么区别,看一下源码: Double.parseDouble(String str) public static double parseDouble(String s) ...

  4. backbone测试代码

    一.入门测试 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  5. 卡特兰数 HDU2067 & HDU4165 & HDU1134

    题目链接:https://vjudge.net/problem/HDU-2067 小兔的棋盘 Time Limit: 1000/1000 MS (Java/Others)    Memory Limi ...

  6. html5--5-7 绘制圆/弧

    html5--5-7 绘制圆/弧 学习要点 掌握arc() 方法创建圆弧/曲线(用于创建圆或部分圆) 矩形的绘制方法 rect(x,y,w,h)创建一个矩形 strokeRect(x,y,w,hx,y ...

  7. hdu-4989 Summary(水题)

    题目链接: Summary Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) P ...

  8. Python: PS 滤镜--USM 锐化

    本文用 Python 实现 PS 滤镜中的 USM 锐化效果,具体的算法原理和效果可以参考之前的博客: http://blog.csdn.net/matrix_space/article/detail ...

  9. bootstrap 学习笔记(1)---介绍bootstrap和栅格系统

    学习前端许久,对于布置框架和响应浏览器用html 和javascript 写的有点繁琐,无意间看到这个框架,觉得挺好用的就开始学习了,但是这个框架上面有很多知识,不是所有的都要学的,故将学习笔记和觉得 ...

  10. [Balkan 2007] Mokia

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1176 [算法] CDQ分治 + 树状数组即可 时间复杂度 : O(Nlog^2N) ...