关于在项目中遇到代码里面写for循环查询这件事

文章探讨了在项目开发中如何避免在for循环中频繁查询,特别是在分页场景下,通过条件分割和自定义SQL/数据库视图的方式减少数据库交互次数,提升性能。同时,也提及了Mybatis和JPA/Hibernate的批量插入方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:由于本人最近在项目中看到太多其他人在for里面写查询的案例(看着头痛.....),所以就想着把自己遇到的问题提出来总结一下(以下的案例和代码仅做参考)。希望这篇文章对大家写代码的有所帮助。

1.分页里面的for循环查询

方法一:条件分割

 public List<SysUserVO> selectUserAll(SysUser user) {
        List<SysUserVO> vos = new ArrayList<>();
        //分页查询
        List<SysUser> users = sysUserMapper.selectUserAll(user);
        //将分页数据中需要翻译的值过滤出来
        Set<Integer> classId = users.stream().map(SysUser::getClassId).collect(Collectors.toSet());
        //查询需要翻译的值
        List<SysClassInfo> sysClassInfos = classInfoMapper.selectClassInfoAllById(classId);
        //将需要翻译的值转成Map
        Map<Integer, String> classInfoMap = sysClassInfos.stream().collect(Collectors.toMap(SysClassInfo::getId, SysClassInfo::getName));
        //组装数据
        users.forEach(data -> {
            SysUserVO vo = new SysUserVO();
            BeanUtils.copyProperties(data,vo);
            vo.setClassName(classInfoMap.get(data.getClassId()));
            vos.add(vo);
        });
        return vos;
    }

分析:假设我们分页的数据只有10条,那么也就是我们主表查询出来的数据只有10条数据要进行翻译(页面展示数据),这个时候如果在循环里面写查询一个个的去翻译,那么就会和数据库进行10此交互。那如果数据更大呢?50条?100条?岂不是要查50次?100次?效率可想而知。所以这个时候我们可以通过上面的方法进行优化:

将我们主表中需要翻译的值通过流的方式过滤一下,把它转换成另一个我们需要翻译的从表条件,这个时候我们只需要去从表查询我们需要翻译的那几个值就行了,然后再将它转换成map的形式方便我们取值翻译,最后组装一下就是我们最终需要的分页数据了。

这样做的好处就是:最终我们去数据库交换的次数只有两次。相比之下,我们程序处理的数据肯定是比去数据库一条一条的检索翻译快得多。

那这个时候就有小伙伴问了,那如果我们需要翻译的条件过多的时候,岂不是每次都要进行这样分割的操作,那样的话,代码会不会太臃肿了。问得好!下面我开始介绍第二种写法:

方法二:建视图或自写SQL

自写SQL(以Mybatis为例):

<select id="selectUserAll1" resultMap="SysUserVO">
        SELECT
        a.*,
        b.`name` AS className
        FROM
        ( SELECT * FROM t_user LIMIT #{beginPage},#{endPage} ) AS a
        LEFT JOIN ( SELECT * FROM t_class_info LIMIT #{beginPage},#{endPage} ) AS b ON a.class_id = b.id
        WHERE
        1 =1
        <if test="user.id != null">
            AND a.id = #{user.id}
        </if>
        <if test="user.name != null and user.name != ''">
            AND a.name = #{user.name}
        </if>
        <if test="user.sex != null and user.sex != ''">
            AND a.sex = #{user.sex}
        </if>
        <if test="user.height != null">
            AND a.height = #{user.height}
        </if>
        <if test="user.age != null">
            AND a.age = #{user.age}
        </if>
        <if test="user.number != null and user.number != ''">
            AND a.number = #{user.number}
        </if>
        <if test="user.birthday != null">
            AND a.birthday = #{user.birthday}
        </if>
        <if test="user.classId != null">
            AND a.class_id = #{user.classId}
        </if>
    </select>

 dao层:

List<SysUserVO> selectUserAll1(@Param("user") SysUser user,@Param("beginPage")Integer beginPage,@Param("endPage")Integer endPage);

servie层:

public List<SysUserVO> selectUserAll1(SysUser user) {
        return sysUserMapper.selectUserAll1(user,0,10);
    }

注意:此处我们只是模拟分页的查询条件

分析:这种方式我们可以在service层省去大量的数据处理的操作,但是,弊端也很明显:那就是xml文件不太好维护,如果判断条件没有写好的话,很容易出现问题。而且如果遇到比较复杂的查询,非常考验sql功底。

如果不想在在Mybatis里面写这么复杂的判断条件或者用的是其他的框架(如JPA,Hibernate)。可以考虑在在数据库建视图,原理和自写SQL类似:

代码:

 <select id="selectUserAll2" resultMap="SysUserVO">
        select * from t_class_user_view where 1=1
        <if test="user.id != null">
            AND a.id = #{user.id}
        </if>
        <if test="user.name != null and user.name != ''">
            AND a.name = #{user.name}
        </if>
        <if test="user.sex != null and user.sex != ''">
            AND a.sex = #{user.sex}
        </if>
        <if test="user.height != null">
            AND a.height = #{user.height}
        </if>
        <if test="user.age != null">
            AND a.age = #{user.age}
        </if>
        <if test="user.number != null and user.number != ''">
            AND a.number = #{user.number}
        </if>
        <if test="user.birthday != null">
            AND a.birthday = #{user.birthday}
        </if>
        <if test="user.classId != null">
            AND a.class_id = #{user.classId}
        </if>
    </select>

相信大家肯定这个时候也发现了新的问题,那就是如果用视图的话,在SQL的可塑性就没有那么强了。遇到数据量极大的时候反而没有自写的SQL好用(视图只能在后面带上分页条件)。不过相对的,这种方式对于JPA而言可能是比较好的解决方案。

2.插入时候的for循环

Mybatis插入详见:Mybatis批量插入的几种方式-优快云博客

JPA和Hibernate的插入(如果觉得复杂,其实也可以使用原始的jdbc写,虽然有点复杂,但是效率还是比较高的):有关Hibernate/JPA的批量插入更新_jpa hibernate批量插入@query-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值