buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

发现mybatisplus#Wrapper的一个雷

什么雷?看如下demo代码:

    public void getOne() {
        LambdaQueryWrapper<SbhPlatOrder> wrappers = new LambdaQueryWrapper<>();
        wrappers.eq(SbhPlatOrder::getOrderId, 1L);
        sbhPlatOrderManager.getOne(wrappers);
    }

 这里要说的是其中调用的 eq 方法。该方法在mybatis-plus-core包里的Compare.java接口里。eq 方法的第二个参数,表示的是传给数据字段的值,注意这个参数的类型是 Object。

// 在com.baomidou.mybatisplus.core.conditions.interfaces.Compare.java里
    default Children eq(R column, Object val) {
        return eq(true, column, val);
    }

 

 

上面demo代码中,SbhPlatOrder#orderId 是String类型, 对应到数据库里的字段类型是 varchar。 而demo里给的参数值是个Long型数字。

这种情况下, mybatisplus——严格说,应该是mybatis——生成的sql日志如下,也就是说,sql语句是: SELECT * FROM sbh_plat_order WHERE order_id = 1 

16:40:44.287 DEBUG SbhPlatOrderMapper.selectOne:143 :==> Preparing: SELECT * FROM sbh_plat_order WHERE order_id = ? 
16:40:44.336 DEBUG SbhPlatOrderMapper.selectOne:143 :==> Parameters: 1(Long)

 

but,但是,however,actually,我们期望的SQL语句是: SELECT * FROM sbh_plat_order WHERE order_id = '1' 

 

这个类型不一致会有什么问题吗?

是的,当 order_id字段是主键或有索引时,这个sql无法命中order_id字段上的索引。这在数据表的数据量大的情况下高频执行时,就会出现明显的性能问题。

我的mybatisplus版本是 com.baomidou:mybatis-plus-boot-starter:jar:3.1.2。真希望高版本的mybatisplus可以解决这个类型转换问题,但是很不幸,直到最新的3.5.6,都是如此。

开发中,我们要提防这个雷区。

 


 



 

 

之所以提这个雷(坑),是因为,今天下午,通过监控系统发现,我们系统生产能力突然下降,频繁报无法获取数据库连接。

最终排查出来的原因,竟然是因为mybatisplus的这个“雷”导致的。 数据表 levy_payment_flow 的flow_no字段有唯一索引, SELECT * FROM levy_payment_flow WHERE flow_no = '1642499617556336'   这个SQL走唯一索引,查询会很快。前不久,flow_no字段类型由 bigint 重构成了 varchar(32) 。而程序里的某个角落里依然存在   wrappers.eq(SbhPlatOrder::getFlowNo, Long.parseLong(requestNo));  这样的代码,代码生成的 SELECT * FROM levy_payment_flow WHERE flow_no = 1642499617556336  SQL因为数据类型不匹配,是不会命中这个唯一索引的,导致全表扫描。levy_payment_flow 表存量数据多达1.3kw条,这个全表扫描的SQL执行耗时长达30s。赶上今天系统交易量大,就曝出问题了。 修正程序使SQL命中唯一索引后,就是毫秒级了。

 

posted on 2022-10-26 21:38  buguge  阅读(586)  评论(2编辑  收藏  举报