修复updateByBatch无法使用的问题

今天定位修复了一个比较难的问题。我们的项目将mybatis-plus升级到最新版后,发现了updateByBatch方法无效。最后层层排查下终于定位出这个问题:我们使用的hikari并将auto-commit配置成了false,而当我们使用updateByBatch方法时,有这样的一段逻辑判断:

1
2
3
4
5
6
7

// PgStatement

if (connection.getAutoCommit()) {
    flags |= QueryExecutor.QUERY_SUPPRESS_BEGIN;
}

这个时候得到的flags中就不包含自动提交的标记位,最终导致我们我们的executeBatch执行的sql最终没有提交。所以只需要将这个配置改为true就可以了。

整个定位问题的过程发生了一些匪夷所思的问题,部分在定位的过程解决了,部分没有,先记录下来:

  1. 在同事的电脑上,我们步进的时候发现一行代码没有执行,直接跳过异常部分到了finally,这个很奇怪。以往的经验是我们使用的class文件和我们正在查看的class文件不一致才会导致这个问题,但是同事并没有手动配置class文件,完全是由Idea反编译的class文件。

  2. 我们使用了p6spy,但是只打印了select的sql语句,并没有打印update的语句(这直接导致我们认为update没有被执行,导致我寻找问题的重心一直是update为什么没有执行)。在定位问题的过程中,我发现,我们执行addBatch和executeBatch时,会直接跳过p6spy的Statement(甚至跳过了hikari的statement),这就是为什么p6spy没有打印执行的sql的原因。

  3. 还有一个问题,非常的迷惑,我在查看反射的时候,明明看到传入的是一个A的实例(A实例后面会跟一段描述:wrapping xxx),我在A实例的方法中断点,死活无法正常断到,我必须去wraping的实例中进行断点。甚至有些时候我去wrapping实例中断点,也无法成功的断点,我有点怀疑这些wrapping的实例时动态生成的。如果真的是这样,动态生成的实例,简直是调试的魔鬼。当然在这个场景下,我总结了一些定位问题的技巧,稍后会整理一下。

这次解决问题的过程中,我收获颇丰,整理如下:

  1. 学会了调式反射代码。

  2. 大致了解了MyBatis中整体架构,下次出问题了,知道该如何排查了。

  3. 因为了解了MyBatis的一些特点,所以我知道在定位问题中,不要被表象迷惑,可以直接在驱动器类上打断点。

  4. 简单了看了一下我们项目中MyBatis部分的架构,感觉功能挺丰富的,只是我在纠结,定制化过高,会不会不利于升级?

这次解决问题的过程中,我也产生了一些新的问题:

  1. 如果代码时动态生成了,我又该如何进行调试呢?