Mybatis篇:Mybatis一对多、多个多对多、加分页、排序、where动态条件,以及分页后数据不匹配的解决方案

目录

 

前言

资料准备

需求1:查询用户列表同时查询用户积分(简单左外连接)

需求2:查询用户列表同时查询用户积分、所属岗位(左外连接+1个多对多)

需求3:查询用户列表同时查询用户积分、所属岗位、所属角色(左外连接+2个多对多)

需求4:查询用户列表同时查询用户积分、所属岗位、所属角色、加分页(左外连接+2个多对多+分页)

需求5:查询用户列表同时查询用户积分、所属岗位、所属角色、加分页、加排序(按注册时间)(左外连接+2个多对多+分页+排序)

需求6:查询用户列表同时查询用户积分、所属岗位、所属角色、加分页、加排序(按注册时间)、加where条件(动态SQL)(左外连接+2个多对多+分页+排序+where条件)

参考资料


前言

因为是在公司项目上写的一些测试代码,这里就不分享整个项目了,只贴上重要的代码,希望对您有帮助hahaha。

资料准备

测试数据库表(无需积分,点击即可下载):zyykin_test_db

不想看贴代码的可以直接跳到后半段看SQL

贴上代码:UserMapper.xml(先贴上完整代码,后面会有拆分解释

<?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.***.***.modules.system.mapper.UserMapper">
    <!-- 查询映射结果 -->
    <resultMap id="userResultMap" type="com.***.***.modules.system.service.dto.UserDto">
        <id column="user_id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="create_time" property="createTime"></result>
        <result column="points" property="points"></result>
        <collection property="roles" ofType="com.***.***.modules.system.service.dto.RoleDto">
            <id property="id" column="role_id"/>
            <result property="name" column="role_name"/>
            <result property="level" column="role_level"/>
        </collection>
        <collection property="jobs" ofType="com.***.***.modules.system.service.dto.JobDto">
            <id property="id" column="job_id"/>
            <result property="name" column="job_name"/>
        </collection>
    </resultMap>
    <select id="getUsers" resultMap="userResultMap">
        SELECT
            sys_user.user_id,
            sys_user.username,
            sys_user.create_time,
            points.points,
            users_jobs.job_id,
            sys_job.`name` job_name,
            users_roles.role_id,
            sys_role.`name` role_name,
            sys_role.LEVEL role_level
        FROM
            sys_user
            LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
            LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
            LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
            LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
            LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id
        WHERE
            sys_user.user_id IN (
            SELECT
                table1.user_id
            FROM
                (
                SELECT DISTINCT
                    sys_user.user_id,
                    sys_user.create_time
                FROM
                    sys_user
                    LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
                    LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
                    LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
                    LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
                    LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id
                <where>
                    <if test="criteria.enabled != null">
                        AND sys_user.enabled = #{criteria.enabled}
                    </if>
                    <if test="criteria.referer != null">
                        AND sys_user.referer = #{criteria.referer}
                    </if>
                </where>
                ORDER BY
                    sys_user.create_time DESC
                LIMIT #{begin}, #{size}
                ) AS table1
            )
        ORDER BY
            sys_user.create_time DESC;
    </select>
</mapper>

贴上代码:DTO类

UserDto类

/**
 * @author zyykin
 * @date 2021/2/24
 * 用户DTO
 */
@Data
public class UserDto implements Serializable {

    /**
     * 用户ID
     */
    private Long id;

    /**
     * 角色集合
     */
    private Set<RoleDto> roles;

    /**
     * 岗位集合
     */
    private Set<JobDto> jobs;

    /**
     * 用户名称
     */
    private String username;

    /**
     * 注册日期
     */
    private Timestamp createTime;
}

RoleDto类

/**
 * @author zyykin
 * @date 2021/2/24
 * 角色DTO
 */
@Data
public class RoleDto implements Serializable {

    /**
     * 角色ID
     */
    private Long id;

    /**
     * 角色名称
     */
    private String name;

    /**
     * 角色等级
     */
    private Integer level;
}

JobDto类

/**
 * @author zyykin
 * @date 2021/2/24
 * 岗位DTO
 */
@Data
public class JobDto implements Serializable {

    /**
     * 岗位ID
     */
    private Long id;

    /**
     * 岗位名称
     */
    private String name;
}

UserMapper类

/**
 * @author zyykin
 * @date 2020/9/16
 */
public interface UserMapper {

    /**
     * 获取用户
     *
     * @param begin    从第几条数据开始
     * @param size     每页显示记录数
     * @param criteria 封装查询条件的类
     * @return
     */
    List<UserDto> getUsers(@Param("begin") long begin, @Param("size") long size, @Param("criteria") UserQueryCriteria criteria);
}

UserQueryCriteria类

/**
 * @author zyykin
 * @date 2021/2/23
 * UserQueryCriteria是封装查询条件的类,也就是拼接在where后面的条件
 */
@Data
public class UserQueryCriteria implements Serializable {

    /**
     * 是否开启
     */
    private Boolean enabled;

    /**
     * 注册来源
     */
    private String referer;
}

---接下来是拆分需求

select字段注释:

需求1:查询用户列表同时查询用户积分(简单左外连接)

tips:下面只贴SQL,只需要替换一下UserMapper.xml中的SQL即可测试

SELECT
	sys_user.user_id,
	sys_user.username,
	sys_user.create_time,
	points.points 
FROM
	sys_user
	LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id;

需求2:查询用户列表同时查询用户积分所属岗位(左外连接+1个多对多)

SELECT
	sys_user.user_id,
	sys_user.username,
	sys_user.create_time,
	points.points,
	users_jobs.job_id,
	sys_job.`name` job_name 
FROM
	sys_user
	LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
	LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
	LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id

需求3:查询用户列表同时查询用户积分所属岗位所属角色(左外连接+2个多对多)

SELECT
	sys_user.user_id,
	sys_user.username,
	sys_user.create_time,
	points.points,
	users_jobs.job_id,
	sys_job.`name` job_name,
	users_roles.role_id,
	sys_role.`name` role_name,
	sys_role.`level` role_level  
FROM
	sys_user
	LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
	LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
	LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
	LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
	LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id

需求4:查询用户列表同时查询用户积分所属岗位所属角色加分页(左外连接+2个多对多+分页)

错误写法:(导致数据不匹配)

原因:多对多情况下,直接使用LIMIT,会导致数据不匹配(数据变少)

SELECT
	sys_user.user_id,
	sys_user.username,
	sys_user.create_time,
	points.points,
	users_jobs.job_id,
	sys_job.`name` job_name,
	users_roles.role_id,
	sys_role.`name` role_name,
	sys_role.`level` role_level  
FROM
	sys_user
	LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
	LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
	LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
	LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
	LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id 
	LIMIT #{begin}, #{size}

正确写法:

解释:根据from后面表的关系,查出userId(去重),LIMIT,再做一次子查询就可以得到想要的结果。

SELECT
	sys_user.user_id,
	sys_user.username,
	sys_user.create_time,
	points.points,
	users_jobs.job_id,
	sys_job.`name` job_name,
	users_roles.role_id,
	sys_role.`name` role_name,
	sys_role.`level` role_level  
FROM
	sys_user
	LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
	LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
	LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
	LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
	LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id 
WHERE
	sys_user.user_id IN (
	SELECT
		table1.user_id 
	FROM
		(
		SELECT DISTINCT
			sys_user.user_id 
		FROM
			sys_user
			LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
			LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
			LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
			LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
			LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id 
			LIMIT #{begin}, #{size}
		) AS table1 
	)

需求5:查询用户列表同时查询用户积分所属岗位所属角色加分页加排序(按注册时间)(左外连接+2个多对多+分页+排序)

tips:这里用了两次:ORDER BY sys_user.create_time DESC

原因:第1次order by是为了limit出最近的userId;第2次order by:在多对多的情况下,某些关联表的字段有默认排序,会导致最终的结果乱序,所以需求再order by一次(当然在前端处理也行)

SELECT
	sys_user.user_id,
	sys_user.username,
	sys_user.create_time,
	points.points,
	users_jobs.job_id,
	sys_job.`name` job_name,
	sys_job.job_sort,
	users_roles.role_id,
	sys_role.`name` role_name,
	sys_role.`level` role_level 
FROM
	sys_user
	LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
	LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
	LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
	LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
	LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id 
WHERE
	sys_user.user_id IN (
	SELECT
		table1.user_id 
	FROM
		(
		SELECT DISTINCT
			sys_user.user_id,
			sys_user.create_time 
		FROM
			sys_user
			LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
			LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
			LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
			LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
			LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id 
		ORDER BY
			sys_user.create_time DESC 
			LIMIT #{begin}, #{size} 
		) AS table1 
	) 
ORDER BY
	sys_user.create_time DESC

需求6:查询用户列表同时查询用户积分所属岗位所属角色加分页加排序(按注册时间)加where条件(动态SQL)(左外连接+2个多对多+分页+排序+where条件)

SELECT
	sys_user.user_id,
	sys_user.username,
	sys_user.create_time,
	points.points,
	users_jobs.job_id,
	sys_job.`name` job_name,
	users_roles.role_id,
	sys_role.`name` role_name,
	sys_role.`level` role_level 
FROM
	sys_user
	LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
	LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
	LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
	LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
	LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id 
WHERE
	sys_user.user_id IN (
	SELECT
		table1.user_id 
	FROM
		(
		SELECT DISTINCT
			sys_user.user_id,
			sys_user.create_time 
		FROM
			sys_user
			LEFT JOIN fc_points_statistics points ON sys_user.user_id = points.user_id
			LEFT JOIN sys_users_jobs users_jobs ON sys_user.user_id = users_jobs.user_id
			LEFT JOIN sys_job ON users_jobs.job_id = sys_job.job_id
			LEFT JOIN sys_users_roles users_roles ON users_roles.user_id = sys_user.user_id
			LEFT JOIN sys_role ON sys_role.role_id = users_roles.role_id 
			<where>
					<if test="criteria.enabled != null">
							AND sys_user.enabled = #{criteria.enabled}
					</if>
					<if test="criteria.referer != null">
							AND sys_user.referer = #{criteria.referer}
					</if>
			</where>
		ORDER BY
			sys_user.create_time DESC 
			LIMIT #{begin}, #{size}			
		) AS table1 
	) 
ORDER BY
	sys_user.create_time DESC;

参考资料

mysql官方手册

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
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`等分页插件来设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值