MySQL一对多的数据分页是很是常见的需求,好比咱们要查询商品和商品的图片信息。可是不少人会在这里遇到分页的误区,获得不正确的结果。今天就来分析并解决这个问题。sql
咱们先建立一个简单商品表和对应的商品图片关系表,它们之间是一对多的关系:mybatis
而后我分别写入了一些商品和这些商品对应的图片,经过下面的左链接查询能够看出它们之间具备明显的一对多关系:app
SELECT P.PRODUCT_ID, P.PROD_NAME, PI.IMAGE_URL FROM PRODUCT_INFO P LEFT JOIN PRODUCT_IMAGE PI ON P.PRODUCT_ID = PI.PRODUCT_ID
按照传统的思惟咱们的分页语句会这么写:框架
<resultMap id="ProductDTO" type="cn.felord.mybatis.entity.ProductDTO"> <id property="productId" column="product_id"/> <result property="prodName" column="prod_name"/> <collection property="imageUrls" ofType="string"> <result column="image_url"/> </collection> </resultMap> <select id="page" resultMap="ProductDTO"> SELECT P.PRODUCT_ID, P.PROD_NAME,PI.IMAGE_URL FROM PRODUCT_INFO P LEFT JOIN PRODUCT_IMAGE PI ON P.PRODUCT_ID = PI.PRODUCT_ID LIMIT #{current},#{size} </select>
当我按照预想传入了(0,2)
想拿到前两个产品的数据,结果并非我指望的:url
2020-06-21 23:35:54.515 DEBUG 10980 --- [main] c.f.m.mappers.ProductInfoMapper.page : ==> Preparing: SELECT P.PRODUCT_ID, P.PROD_NAME,PI.IMAGE_URL FROM PRODUCT_INFO P LEFT JOIN PRODUCT_IMAGE PI ON P.PRODUCT_ID = PI.PRODUCT_ID limit ?,? 2020-06-21 23:35:54.541 DEBUG 10980 --- [main] c.f.m.mappers.ProductInfoMapper.page : ==> Parameters: 0(Long), 2(Long) 2020-06-21 23:35:54.565 DEBUG 10980 --- [main] c.f.m.mappers.ProductInfoMapper.page : <== Total: 2 page = [ProductDTO{productId=1, prodName='杯子', imageUrls=[http://asset.felord.cn/cup1.png, http://asset.felord.cn/cup2.png]}]
我指望的两条数据是杯子和笔记本,可是结果却只有一条。原来当一对多映射时结果集会按照多的一侧进行输出(指望4条数据,实际上会有7条),而前两条展现的只会是杯子的数据(如上图),合并后就只有一条结果了,这样分页就对不上了。那么如何才能达到咱们指望的分页效果呢?spa
正确的思路是应该先对主表进行分页,再关联从表进行查询。
抛开框架,咱们的SQL应该先对产品表进行分页查询而后再左关联图片表进行查询:code
SELECT P.PRODUCT_ID, P.PROD_NAME, PI.IMAGE_URL FROM (SELECT PRODUCT_ID, PROD_NAME FROM PRODUCT_INFO LIMIT #{current},#{size}) P LEFT JOIN PRODUCT_IMAGE PI ON P.PRODUCT_ID = PI.PRODUCT_ID
这种写法的好处就是通用性强一些。可是MyBatis提供了一个相对优雅的路子,思路依然是开头所说的思路。只不过咱们须要改造上面的Mybatis XML配置:xml
<resultMap id="ProductDTO" type="cn.felord.mybatis.entity.ProductDTO"> <id property="productId" column="product_id"/> <result property="prodName" column="prod_name"/> <!-- 利用 collection 标签提供的 select 特性 和 column --> <collection property="imageUrls" ofType="string" select="selectImagesByProductId" column="product_id"/> </resultMap> <!-- 先查询主表的分页数据 --> <select id="page" resultMap="ProductDTO"> SELECT PRODUCT_ID, PROD_NAME FROM PRODUCT_INFO LIMIT #{current},#{size} </select> <!--根据productId 查询对应的图片--> <select id="selectImagesByProductId" resultType="string"> SELECT IMAGE_URL FROM PRODUCT_IMAGE WHERE PRODUCT_ID = #{productId} </select>
大部分状况下分页是很容易的,可是一对多仍是有一些小小的陷阱的。一旦咱们了解了其中的机制,也并不难解决。固然若是你有更好的解决方案能够留言讨论,集思广益。多多关注:码农小胖哥,获取更多开发技巧。blog
关注公众号:Felordcn 获取更多资讯
图片