栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

不要使用For循环查询数据了!!!

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

不要使用For循环查询数据了!!!

不要使用For循环查询数据了!!!
      • 1.使用场景
      • 2.菜鸟(我)的写法
      • 3.更看好的写法
      • 4.优缺点

1.使用场景

不多bb直接上问题:

这里有两张表,表关系一对多,开发中常见的需求:
先分页查询出user表下的n条数据,再关联查询出note表中与之关联的数据
比如:分页查询 每页10条用户(user)数据,返回结果需要携带每个用户发表的笔记(note)

2.菜鸟(我)的写法


这段代码只需要关注中间的查询过程
1.先进行分页查询,拿到全部的10条(user)数据。
2.使用循环查询每一条User下的全部note数据
3.组装数据返回
问题:只看结果的话,这样写好像也没啥毛病,可以拿到想要的数据,但是!!!我们来看一下我们查询了几次数据库 如果我没数错 11次!!! 这是每页10条数据,如果每页20条或者50条数据呢?

刚开始遇到类似的需求,我也都是使用上面的方式,刚开始学的时候我也想过有没有更好的方法呢?我还看了其他人写的代码,好像都是这样写的 直到我学会了下面的这个方式
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

3.更看好的写法


这段代码我们还是只关注查询数据的方式
1.先进行分页查询,拿到全部的10条(user)数据。(不变)
2.拿到10条数据的userId,使用关键词“in”查询我们需要的全部数据
3.使用Collectors.groupingBy分组
4.组装数据返回(拿到的数据完全一样)
问题:这段代码相对第一种方式有点点难度,不过认真看一下还是蛮简单的,我们先看一下这次我们查询了几次数据库 没数错的话 2次! 相对之前的方法查询数据库次数变少了 那么时间呢?请看

次数第一种时间(ms)第二种时间(ms)
1236
2215
3197
4206
5216

以上数据使用 Postman 测试得到

4.优缺点

对比上面的两种方法,代码量来看 第一种更简单,更容易理解;第二种代码相对更复杂。效率来看 第二种方法优于第一种,毕竟程序在内存中的计算比反复的查询数据库花费的时间更少,更快一点。
我也只是针对很少数据进行了测试 user表:10条 note表:50条
感兴趣的小伙伴可以尝试更多的数据,如果本篇博客有技术性错误,欢迎留言批评☻☻☻

下面给到重点的代码和素材表结构
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
代码块1:

@GetMapping("list1")
    public R getUserList1(){
        long time_start = new Date().getTime(); //开始时间

        Page page = new Page<>(1, 10); //分页   查询10个
        userService.page(page, null);
        //查询出 UserList 进行遍历查询 Note
        List userList = page.getRecords();
        List collect = userList.stream().map(user -> {
            Long userId = user.getId();
            List list = noteService.list(new LambdaQueryWrapper().eq(NoteEntity::getUserId, userId));
            UserRes userRes = new UserRes();
            BeanUtils.copyProperties(user, userRes);
            userRes.setNoteList(list);
            return userRes;
        }).collect(Collectors.toList());

        long time_end = new Date().getTime(); //结束时间
        //返回结果数据 完全一样
        return R.ok().put("data",collect).put("atime",time_end-time_start);
    }

代码块2

@GetMapping("list2")
    public R getUserList2(){
        long time_start = new Date().getTime(); //开始时间

        Page page = new Page<>(1, 10); //分页
        userService.page(page, null); //条件一致

        //查询出 UserList 非遍历查询 使用'in'关键字一次查询出所有需要的数据
        List userList = page.getRecords();
        List userIdList = userList.stream().map(UserEntity::getId).collect(Collectors.toList());
        List list = noteService.list(new LambdaQueryWrapper().in(NoteEntity::getUserId, userIdList));
        //使用Collectors.groupingBy分组并组装数据
        Map> NoteListMap = list.stream().collect(Collectors.groupingBy(NoteEntity::getUserId));
        List collect = userList.stream().map(user -> {
            UserRes userRes = new UserRes();
            BeanUtils.copyProperties(user, userRes);
            userRes.setNoteList(NoteListMap.get(user.getId()));
            return userRes;
        }).collect(Collectors.toList());
        long time_end = new Date().getTime();
        //返回结果数据 完全一样
        return R.ok().put("data",collect).put("atime",time_end-time_start);

    }

表结构(数据自造)

CREATE TABLE `notes_note` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `title` varchar(50) DEFAULT NULL COMMENT '标题',
  `user_id` bigint(20) DEFAULT NULL COMMENT '作者',
  `content` longtext COMMENT '内容',
  `type` tinyint(1) DEFAULT NULL COMMENT '类型 rn1.文本 rn2.视频(url) rn3.pdf(url) rn4.图片(url) rn5.音乐(url) rn6.html(url)',
  `lable` varchar(20) DEFAULT NULL COMMENT '内容分组/标签 ',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
  `is_deleted` tinyint(1) DEFAULT '0' COMMENT '0可用 1不可用',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='笔记表';

CREATE TABLE `notes_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `nick_name` varchar(20) DEFAULT NULL COMMENT '昵称',
  `user_name` varchar(20) NOT NULL COMMENT '用户名',
  `email` varchar(30) DEFAULT NULL COMMENT '邮箱地址',
  `password` varchar(30) DEFAULT NULL COMMENT '密码',
  `salt` varchar(30) DEFAULT NULL COMMENT '密码加密盐',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
  `is_deleted` tinyint(1) DEFAULT '0' COMMENT '是否删除 0可用 1删除',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `user_name` (`user_name`) USING BTREE COMMENT '账号 索引',
  KEY `email` (`email`) USING BTREE COMMENT '邮箱地址索引'
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='用户表';

R、Res:

public class R extends HashMap {
	private static final long serialVersionUID = 1L;

	public R() {
		put("code", 0);
	}

	public static R error() {
		return error(500, "未知异常,请联系管理员");
	}

	public static R error(String msg) {
		return error(500, msg);
	}

	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}

	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}

	public static R ok(Map map) {
		R r = new R();
		r.putAll(map);
		return r;
	}

	public static R ok() {
		return new R();
	}

	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}
//----------------------------------------------------------------------------------//
@Data
@Accessors(chain = true)
public class UserRes extends UserEntity {

    private List noteList;
    
}

如果对Collectors.groupingBy用法不了解请看:
java8中的Collectors.groupingBy用法

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/301129.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号