Mybatis 的 foreach 为什么会出现性能问题

背景

最近在做一个类似于综合报表之类的东西,需要查询所有的记录(数据库记录有限制),大概有1W条记录。该报表需要三个表的数据,也就是根据这 1W 个 ID 去执行查询三次数据库,其中,有一条查询 SQL 是自己写,其他两条是根据别人提供的接口进行查询。

刚开始的时候,没有多想,直接使用 in 进行查询,使用 Mybatis 的 foreach 语句;项目中使用的是 jsonrpc 来请求数据,在测试的时候,发现老是请求不到数据,日志抛出的是 jsonrpc 超时异常,继续查看日志发现,是被阻塞在上面的三条SQL查询中。

在以前分析 Mybatis 的源码的时候,了解到,Mybatis 的 foreach 会有性能问题,所以改了下 SQL,直接在代码中拼接SQL,然后在 Mybatis 中直接使用 # 来获取,替换 class 测试了下,果然一下子就能查询出数据。

前提

这里先不考虑使用 in 好不好,如何去优化 in,如何使用 exists 或 inner join 进行代替等,这里就只是考虑使用了 in 语句,且使用了 Mybatis 的 foreach 语句进行优化,其实 foreach 的优化很简单,就是把 in 后面的语句在代码里面拼接好,在配置文件中直接通过 #{xxx} 或 ${xxx} 当作字符串直接使用即可。

测试

在分析 foreach 源码之前,先构造个数据来看看它们的区别有多大。

建表语句:

CREATE TABLE person
(
    id int(11) PRIMARY KEY NOT NULL,
    name varchar(50),
    age int(11),
    job varchar(50)
);

插入 1W 条数据:

POJO 类:

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Serializable {
    private int id;
    private String name;
    private String job;
    private int age;
}

方式一

通过原始的方式,使用 foreach 语句:

1. 在 dao 里面定义方法:

List<Person> queryPersonByIds(@Param("ids") List<Integer> ids);

2. 配置文件SQL:

<select id="queryPersonByIds" parameterType="list" resultMap="queryPersonMap">
    select * from person where 1=1
    <if test="ids != null and ids.size() > 0">
        and id in
        <foreach collection="ids" item="item" index="index" separator="," open="(" close=")">
            #{item}
        </foreach>
    </if>
</select>

3. 执行 main 方法:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-mybatis.xml" })
public class MainTest {

    @Autowired
    private IPersonService personService;

    @Test
    public void test(){
        // 构造 1W 个 ID
        List<Integer> ids = new ArrayList<>();
        for (int i = 1; i <= 10000; i++) {
            ids.add(i);
        }
        long start = Syst
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值