Mybatis Invalid bound statement
前两天在项目中遇到个很神奇的问题,想着周末有空的时候给解一下
问题的现象
在IDEA中执行main方法能正常跑通程序</br>
但是打包后,执行jar包会报错,错误信息如下:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
是在调用Mapper方法的时候抛出的异常

大胆猜测,小心求证
此时心中隐隐有答案,猜测大概率是数据源有问题,为了求证心中所想
我在报错的地方打了个断点,在两种不同的场景下分别进行调试
main调试
查看Mapper对应的数据源信息

jar包调试
使用调试模式执行jar包,打开命令行执行下面命令
java -Xdebug -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=y -jar main.jar
在IDEA中配置端口号
- 添加新的配置 选择Remote JVM Debug
- 填写Host: localhost Port: 5000
- -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5000


经过对比发现,Mapper注入的数据源果真是不一样的!
为什么会不一样呢???
代码都是一样的,配置也一样的,为啥打完jar后执行 注入的数据源就不同!
这时会怀疑是不是打包有问题,然后又解压了jar包去看,发现Mapper文件,数据源配置也都在,那大概可以排除是打包的问题了。
这条路走不通,那就换个思路去查一波
现在是可以定位到Mapper注入的数据源是异常的,那就查一下Mapper在注入这个数据源的时候发生了啥
那么Mapper是什么时候被Spring扫描的呢?
看一下spring-mybatis.xml配置文件发现配置了一个bean MapperScannerConfigurer
这个bean注入了扫描的mapper包位置和注入的数据源信息


MapperScannerConfigurer类说明会从basePackage包开始递归实例化Mapper接口
好,那就先断个点在注入Mapper包(basePackage)的地方,debug看看,

观察一下前面执行的栈

- 在PostProcessorRegistrationDelegate中调用了invokeBeanFactoryPostProcessors
方法 - 该方法会获取BeanDefinitionRegistryPostProcessor类型的需要实例化的beanName列表
- 而MapperScannerConfigurer刚好继承BeanDefinitionRegistryPostProcessor
- 接着调用beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)去实例化该bean
好了,到了这,真相快大白了,前面的时候我们已经知道Mapper是注入了别的数据源,而项目中的数据源也比较多,那就有可能是别的配置文件里也扫描了该Mapper
然后谁先搜索到该Mapper就会注入该类型的数据源
果不其然,翻了别的配置文件一看,有个basePackage使用了通配符匹配,把该Mapper也扫描了进去!!!

为了验证是不是这个原因,我把该basePackage改了一下,不要扫描到该Mapper,打包执行,程序跑通了!没想到没想到。
再深入挖一下
问题出现的前提条件
- 项目中有多个spring-xxx.xml配置文件
- 打成jar包,使用java -jar执行
那接着来看看spring扫描配置文件在不同场景下的做法
通过debug后定位到方法org.springframework.core.io.support.PathMatchingResourcePatternResolver#findPathMatchingResources
该方法会返回一个Resource数组,表示扫描的配置文件顺序

- doFindPathMatchingJarResources: 查找Jar文件里的配置文件
很正常的通过迭代器获取文件

- doFindPathMatchingFileResources: 查找文件系统内的配置文件
这里的方法调用链会比较深,最后定位到方法
org.springframework.core.io.support.PathMatchingResourcePatternResolver#doRetrieveMatchingFiles
需要注意的是这里调用了Arrays.sort对文件进行了排序


所以才会有这么戏剧性的bug出现