ShardingSphere分库分表schema名称导致NPE问题排查记录

荔枝岛岛主
发布于 2023-9-27 11:13
浏览
0收藏

前段时间把 ShardingSphere 升级到了 5.1.1 版本,奈何官方版本升级太快跟不上速度,这不最近又发现了一个 BUG。

问题现象

数据库做了分库分表,在需要查询多表数据进行 merge 的时候发生了一个 NPE 的异常。

Caused by: java.lang.NullPointerException
    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.getOrderValuesCaseSensitiveFromTables(OrderByValue.java:73) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.getOrderValuesCaseSensitive(OrderByValue.java:64) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.<init>(OrderByValue.java:58) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByStreamMergedResult.orderResultSetsToQueue(OrderByStreamMergedResult.java:56) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByStreamMergedResult.<init>(OrderByStreamMergedResult.java:50) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.sharding.merge.dql.ShardingDQLResultMerger.build(ShardingDQLResultMerger.java:89) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.sharding.merge.dql.ShardingDQLResultMerger.merge(ShardingDQLResultMerger.java:63) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.infra.merge.MergeEngine.executeMerge(MergeEngine.java:90) ~[shardingsphere-infra-merge-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.infra.merge.MergeEngine.merge(MergeEngine.java:80) ~[shardingsphere-infra-merge-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.mergeQuery(ShardingSpherePreparedStatement.java:487) ~[shardingsphere-jdbc-core-5.1.1.jar:5.1.1]
    at org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.getResultSet(ShardingSpherePreparedStatement.java:435) ~[shardingsphere-jdbc-core-5.1.1.jar:5.1.1]
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getFirstResultSet(DefaultResultSetHandler.java:237) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:187) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) ~[mybatis-3.5.3.jar:3.5.3]
    at jdk.internal.reflect.GeneratedMethodAccessor346.invoke(Unknown Source) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.5.3.jar:3.5.3]
    at com.sun.proxy.$Proxy410.query(Unknown Source) ~[?:?]
    at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:108) ~[pagehelper-5.1.11.jar:?]
    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.5.3.jar:3.5.3]
    at com.sun.proxy.$Proxy410.query(Unknown Source) ~[?:?]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147) ~[mybatis-3.5.3.jar:3.5.3]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) ~[mybatis-3.5.3.jar:3.5.3]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) ~[mybatis-spring-2.0.6.jar:2.0.6]
    ... 95 more

问题排查

跟踪到报错的地方,发现是这个地方的​​schema​​​是个​​null​​,从而引发了 NPE。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

一路往上看代码,最终定位到了这个获取​​schema​​​的地方,也就是元数据去​​getDefaultSchema​​​获取默认的​​schema​​名称改的时候拿到了一个空值。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

进入这个方法后发现通过​​schema​​​去​​schemas​​​这个​​map​​​里获取名称的时候是个空值,​​debug​​到这个地方其实发现了问题。

我们的​​schemaName​​​配置的是​​orderTrade​​​包含有大写字符的,所以​​name​​​传进来的是​​orderTrade​​​,但是问题是这个​​schemas​​​确是​​ordertrade​​。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

所以很显然,这里获取不到正确的​​schema​​​名称,导致了这个 NPE 的异常,那么问题是这个​​schemas​​是怎么加载进来的呢?

我们发现​​schemas​​是在创建元数据的时候,通过构造函数赋值的,那么只要找到这个赋值的地方应该就能发现问题了。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

通过一番查找,找到了调用的地方,这个​​schemas​​​值就是​​databaseMap​​​中的​​value​​​,那么我们要继续看这个​​databaseMap​​是如何初始化来的。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

继续看源码,找到了​databaseMap​进行初始化的地方,原来是通过​DatabaseLoader​去加载元数据的时候初始化的,那么这个​load​方法是怎么处理的呢?

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

从代码来看他包含了两部分的信息,第一个是我们自己通过​schema​配置的一些分库分表的配置信息,另外一部分则是数据库默认的一些表的元数据,比如​mysql​​information_schema​这些,那我们只要看自己配置的那部分就可以了,也就是​SchemaLoader.load(dataSourceMap, rules, props)​方法。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

看他实际上就是获取数据库是什么类型,比如​​mysql​​​,然后去加载表的元数据,最后​​new​​​出来​​ShardingSphereSchema​​​,直接看最后的​​new​​部分代码就行了。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

进入这个方法,瞬间就真相大白了,原来在​​put​​​的时候对所有的​​schemaName​​​进行了小写处理,所以在最上面我们去​​get​​​的时候肯定会拿到一个空值,最终导致​​merge​​的时候发生了 NPE 异常。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

解决方案

现在问题原因已经发现了,那么该如何解决呢?总不能不让别人配置的时候不让写大写吧,本着能不能白嫖一个 PR 的想法,又去给 Sharding 提了一个 Issue。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区

就我点了根烟的功夫,回头就给我回复说新版本已经修复了,希望落空了,修复方案就是查询的时候也做小写处理了,好吧,那就这样吧。

ShardingSphere分库分表schema名称导致NPE问题排查记录-鸿蒙开发者社区




文章转载自公众号:艾小仙

分类
已于2023-9-27 11:13:50修改
收藏
回复
举报
回复
    相关推荐