发现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命中唯一索引后,就是毫秒级了。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/16830176.html