mysql使用mybatis,一对多情况下,根据主表个数分页,一次查询出数据

1 业务详情

rt,两张表user,score,一对多,以user为主表,需要根据user来进行分页查询.想要获取男性,以pageNum=3分页的学生信息和分数信息

2 表

CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `gender` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

CREATE TABLE `score`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `course` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `score` int(1) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;


3 坑

需求: 查询男性,pageSize=3
在mybatis中,使用resultMap 进行映射,此处使用的是直接映射子表结果集,而不是使用select,防止出现n+1次查询问题.此查询问题,不懂的可以google


① 下面sql,为坑

select u.*,s.* from user u 
left join score s on u.id=s.user_id
where u.gender='男'
limit 0,3;

很明显,对于小白来说,很大可能这么写,但是这样写,是获取不到想要结果的…
在这里插入图片描述
② why
其实很简单,最终获取到的是1对多的集,limit是对最终的临时表进行分页,即对最终一对多形成的结果进行分页,而不是根据主表数据分页.

4 解决方案

sql如下:

select u.*,s.* from 
(select u1.* from user u1 where u1.gender='男' limit 0,3)  u 
left join score s on u.id=s.user_id

结果:
在这里插入图片描述

即,先对你想要分页的表进行分页和条件之后,再进行关联查询.这样的结果经过mybatis的resultMap映射后,即可获取到根据user分页的结果

5 注意

当你使用4的sql需要进行排序的时候,子查询需要排序,外面的查询也需要排序
错误sql:

select u.*,s.* from 
(select u1.* from user u1 where u1.gender='男' order by u1.id desc limit 0,3)  u 
left join score s on u.id=s.user_id

错误sql结果:
在这里插入图片描述


正确sql:

select u.*,s.* from 
(select u1.* from user u1 where u1.gender='男' order by u1.id desc limit 0,3)  u 
left join score s on u.id=s.user_id

order by u.id desc

正确sql结果:
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MyBatis支持一对多分页查询,可以通过嵌套查询实现。以下是一个示例,假设我们有两个表:`orders`和`order_items`,一个订单可以对应多个订单项。 ```xml <!-- 定义订单查询SQL --> <select id="getOrders" resultMap="orderResultMap"> select * from orders where user_id = #{userId} </select> <!-- 定义订单项查询SQL --> <select id="getOrderItems" resultMap="orderItemResultMap"> select * from order_items where order_id in <foreach item="orderId" collection="orderIds" open="(" separator="," close=")"> #{orderId} </foreach> </select> <!-- 定义查询订单及其订单项的SQL --> <select id="getOrdersWithItems" resultMap="orderResultMap"> <!-- 分页查询订单 --> select * from orders where user_id = #{userId} limit #{offset}, #{limit} <!-- 查询订单对应的订单项 --> <foreach item="order" collection="orders" open="" close="" separator=""> <bind name="orderIds" value=""/> <foreach item="item" collection="order.items" open="" close="" separator=""> <if test="_databaseId == 'mysql'"> <bind name="orderIds" value="${orderIds + ',' + item.id}"/> </if> <if test="_databaseId == 'postgresql'"> <bind name="orderIds" value="#{orderIds,javaType=java.util.List,jdbcType=ARRAY,mode=OUT}(#{item.id})"/> </if> </foreach> <if test="order.items != null and order.items.size() > 0"> <!-- 分页查询订单项 --> <include refid="getOrderItems"/> </if> </foreach> </select> <!-- 定义订单项映射 --> <resultMap id="orderItemResultMap" type="OrderItem"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="price" column="price"/> </resultMap> <!-- 定义订单映射 --> <resultMap id="orderResultMap" type="Order"> <id property="id" column="id"/> <result property="userId" column="user_id"/> <result property="totalPrice" column="total_price"/> <collection property="items" ofType="OrderItem"> <result property="id" column="id"/> <result property="name" column="name"/> <result property="price" column="price"/> </collection> </resultMap> ``` 在上面的示例中,`getOrdersWithItems`是我们要执行的查询,它首先查询订单表,然后对每个订单查询对应的订单项。我们使用`foreach`标签来遍历订单列表,对于每个订单,我们将其对应的订单项的`id`拼接成一个字符串,然后传递给`getOrderItems`查询语句中的`in`条件。注意,为了支持不同的数据库,我们使用了不同的语法来传递`in`条件,MySQL使用`${}`,PostgreSQL使用`#{}`。同时,我们在`if`标签中判断订单是否有对应的订单项,如果没有,则不执行查询。 另外,为了支持分页查询,我们使用了`limit`和`offset`参数。`limit`表示每页查询多少条记录,`offset`表示从第几条记录开始查询。这些参数可以通过`PageHelper`等分页插件来设置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值