Mybatis Plus一对多联表查询及分页解决方案
创始人
2024-02-01 09:25:59
0

文章目录

    • 需求
    • 需求分析
    • 分页问题说明
    • 分页问题原因
    • 一对多场景一
    • 一对多场景二
    • 性能优化
      • 优化解决方案

需求

查询用户信息列表,其中包含用户对应角色信息,页面检索条件有根据角色名称查询用户列表;

需求分析

一个用户对应多个角色,用户信息和角色信息分表根据用户id关联存储,用户和角色一对多进行表连接查询,

创建对应表:

CREATE TABLE `sys_user` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',`name` varchar(50) DEFAULT NULL COMMENT '姓名',`age` int DEFAULT NULL COMMENT '年龄',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4  COMMENT='用户信息表';CREATE TABLE `sys_role` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色ID',`role_name` varchar(30) NOT NULL COMMENT '角色名称',PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4  COMMENT='角色信息表';CREATE TABLE `sys_user_role` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',`user_id` bigint NOT NULL COMMENT '用户ID',`role_id` bigint NOT NULL COMMENT '角色ID',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4  COMMENT='用户和角色关联表';INSERT INTO tsq.sys_user (name,age) VALUES('张三',18),('王二',19);INSERT INTO tsq.sys_role (role_name) VALUES('角色1'),('角色2'),('角色3'),('角色4');INSERT INTO tsq.sys_user_role (user_id,role_id) VALUES(1,1),(1,2),(1,3),(2,4);

对应实体类:

@Data
@ApiModel("用户信息表")
@TableName("sys_user")
public class User implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty("用户id")private Long id;@ApiModelProperty("姓名")private String name;@ApiModelProperty("年龄")private Integer age;
}@Data
@ApiModel("角色信息表")
@TableName("sys_role")
public class Role implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty("角色id")private Long id;@ApiModelProperty("角色名称")private String roleName;
}@Data
@ApiModel("用户信息表")
public class UserVo implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty("用户id")private Long id;@ApiModelProperty("姓名")private String name;@ApiModelProperty("年龄")private Integer age;private List roleList;}

分页问题说明

在使用一对多连接查询并且分页时,发现返回的分页列表数据数量不对
比如这里查询用户对应角色列表,如果使用直接映射,那么 roleList 的每个 Role 对象都会算一条数据;比如查第一页,一个用户有三个角色每页三条数据,就会出现查出一个 User ,三个 Role 的这些情况,这它也算每页三条(其实就只查到一个用户)

分页问题原因

mybatis-plus一对多分页时,应该使用子查询的映射方式,使用直接映射就会出错
所以直接映射适用于一对一,子查询映射使用于一对多;

一对多场景一

查询用户表的内容,角色表不参与条件查询,用懒加载形式

// controller@GetMapping("/pageList")public Map pageList(@RequestParam(required = false, defaultValue = "0") int offset,@RequestParam(required = false, defaultValue = "10") int pagesize) {return userService.pageList(offset, pagesize);}// serviceimpl@Overridepublic Map pageList(int offset, int pagesize) {List pageList = userMapper.pageList(offset, pagesize);int totalCount = userMapper.pageListCount();Map result = new HashMap();result.put("pageList", pageList);result.put("totalCount", totalCount);return result;}// mapper.xml

查询结果
图片alt

一对多场景二

查询用户表的内容,角色表要作为查询条件参与查询,例如要根据角色名称查询出用户列表

// controller@GetMapping("/pageListByRoleName")public Map pageListByRoleName(@RequestParam(required = false, defaultValue = "0") int offset,@RequestParam(required = false, defaultValue = "10") int pagesize,@RequestParam String roleName) {return userService.pageListByRoleName(offset, pagesize, roleName);}// serviceimpl@Overridepublic Map pageListByRoleName(int offset, int pagesize,String roleName) {List pageList = userMapper.pageListByRoleName(offset, pagesize, roleName);int totalCount = userMapper.pageListCount();Map result = new HashMap();result.put("pageList", pageList);result.put("totalCount", totalCount);return result;}// mapper.xml

查询结果
在这里插入图片描述

性能优化

原因:

场景一二中使用 select方式会触发多次子查询(SELECT *FROM sys_user_role ur inner join sys_role …),当数据量大时会使查询速度很慢。

场景二中查询时产生的sql日志如下:

--  ==>  
SELECTtemp.* 
FROM( SELECTdistinct u.*,'角色' as roleName FROMsys_user u left joinsys_user_role ur on u.id = ur.user_id left joinsys_role r on r.id = ur.role_id WHEREr.role_name LIKE concat('%', '角色', '%') ) temp LIMIT 0,10 --  ====>  
SELECT* 
FROMsys_user_role ur 
inner joinsys_role r on ur.role_id = r.id 
whereur.user_id = 1 and r.role_name LIKE concat('%', '角色', '%') --  ====>  
SELECT* 
FROMsys_user_role ur 
inner joinsys_role r on ur.role_id = r.id 
whereur.user_id = 2 and r.role_name LIKE concat('%', '角色', '%') --  ==>  
SELECTcount(1) 
FROMsys_user 

sql可见如果有100各用户就要执行一百次子查询,效率极低。

优化解决方案

sql中只查询sys_user相关信息并且做roleName 过滤,roleList在java代码中用stream关联role并赋值roleList;

// serviceimpl@Overridepublic Map pageListByRoleName(int offset, int pagesize,String roleName) {// List pageList = userMapper.pageListByRoleName(offset, pagesize, roleName);List pageList = userMapper.pageListByRoleName2(offset, pagesize, roleName);List userIds = pageList.stream().map(UserVo::getId).collect(Collectors.toList());List userRoleVos =  userMapper.getUserRoleByUserIds(userIds);Map> userRoleMap = userRoleVos.stream().collect(Collectors.groupingBy(UserRoleVo::getUserId, Collectors.toList()));pageList.forEach(u -> {List roleVos = userRoleMap.get(u.getId());List roles = BeanUtils.listCopy(roleVos, CopyOptions.create(), RoleVo.class);u.setRoleList(roles);});int totalCount = userMapper.pageListCount();Map result = new HashMap();result.put("pageList", pageList);result.put("totalCount", totalCount);return result;}// mapper.xml
  

查询结果

同场景二。

查询时产生的sql如下:

  --  ==>  SELECTdistinct u.* FROMsys_user u left joinsys_user_role ur on u.id = ur.user_id left joinsys_role r on r.id = ur.role_id WHEREr.role_name LIKE concat('%', '角色', '%') LIMIT 0, 10 --  ==>  SELECTur.user_id ,r.id roleId,r.role_name FROMsys_user_role ur inner joinsys_role r on ur.role_id = r.id --  ==>  SELECTcount(1) FROMsys_user 

由sql日志可见这种方式比纯sql方式效率高一些

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...