ShardingSphere前段时间升级到5.1.1版本,但是正式版升级速度太快跟不上,最近发现了一个bug.问题现象是数据库已经分库和表了。当需要查询多表数据进行merge时,出现NPE异常。由:java.lang.NullPointerException在org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.getOrderValuesCaseSensitiveFromTables(OrderByValue.java:73)~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.getOrderValuesCaseSensitive(OrderByValue.java:64)~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.(OrderByValue.java:58)~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.sharding.merge。dql.orderby.OrderByStreamMergedResult.orderResultSetsToQueue(OrderByStreamMergedResult.java:56)~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByStreamMergedResult.(OrderByStreamMergedResult.java:50)~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.sharding。merge.dql.ShardingDQLResultMerger.build(ShardingDQLResultMerger.java:89)~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.sharding.merge.dql.ShardingDQLResultMerger.merge(ShardingDQLResultMerger.java:63)~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.infra.merge.MergeEngine.executeMerge(MergeEngine.java:90)~[shardingsphere-infra-merge-5.1.1.jar:5.1.1]在org.apache.shardingsphere.infra.merge.MergeEngine.merge(MergeEngine.java:80)~[shardingsphere-infra-merge-5.1.1.jar:5.1.1]在org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.mergeQuery(ShardingSpherePreparedStatement.java:487)~[shardingsphere-jdbc-core-5.1.1.jar:5.1.1]在org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.getResultSet(ShardingSpherePreparedStatement.java:435)~[shardingsphere-jdbc-core-5.1.1.jar:5.1.1]在org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getFirstResultSet(DefaultResultSetHandler.java:237)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:187)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)~[mybatis-3.5.3.jar:3.5.3]atjdk.internal.reflect.GeneratedMethodAccessor346.invoke(未知来源)~[?:?]在jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)~[?:?]在java.lang.reflect。Method.invoke(Method.java:566)~[?:?]在org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63)~[mybatis-3.5.3.jar:3.5.3]com.sun.proxy.$Proxy410.query(UnknownSource)~[?:?]在com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:108)~[pagehelper-5.1.11.jar:?]在org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)~[mybatis-3.5.3.jar:3.5.3]在com.sun.proxy.$Proxy410.query(UnknownSource)~[?:?]在org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)~[mybatis-3.5.3.jar:3.5.3]在org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)~[mybatis-3.5.3.jar:3.5.3]在jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(本机方法)~[?:?]在jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)~[?:?]在jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)~[?:?]在java.lang.reflect.Method.invoke(Method.java:566)~[?:?]在org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427)~[mybatis-spring-2.0.6.jar:2.0.6]...95moreTroubleshooting跟踪到报错的地方,发现这个地方的schema为null,导致NPE查找代码all顺便说一句,最后定位到了这个获取schema的地方,也就是metadata去getDefaultSchema获取默认schema名称的时候,获取到了一个null值。进入这个方法后,发现去schema的map中通过schema获取name时,是null值。当我调试到这个地方的时候,其实发现了一个问题。我们的schemaName配置是orderTrade包含大写字符,所以传入的名称是orderTrade,但问题是schemas确实是ordertrade。那么很明显,这里无法获取到正确的schema名称,从而导致了NPE异常,那么问题来了,schema是如何加载进来的呢?我们发现schema是在元数据创建的时候通过构造函数赋值的,所以只要找到赋值的地方,应该就能找到问题所在。经过一番寻找,我们找到了调用的地方。模式的值是databaseMap中的值。那么我们需要继续看databaseMap是如何初始化的。继续查看源码,找到了初始化databaseMap的地方。本来是在通过DatabaseLoader加载元数据的时候初始化的,那么这个load方法是怎么处理的呢?从代码来看,它包含两部分信息。第一部分是我们通过schema配置的一些分库和表的配置信息,另一部分是数据库中一些默认表的元数据,比如mysql,information_schema。那么我们只需要看一下我们配置的部分,就是SchemaLoader.load(dataSourceMap,rules,props)方法。看实际是什么类型的数据库,比如mysql,然后加载表的元数据,最后new出ShardingSphereSchema,看最后new的部分代码就好了。进入这个法门,瞬间真相大白。原来在put的时候所有的schemaNames都是小写的,所以我们去get到top的时候肯定会得到一个null值,最终导致合并的时候出现NPE异常。.解决方案既然已经找到了问题的原因,那该如何解决呢?我在配置的时候不能阻止别人写大写字母。本着能不能白做PR的想法,就去提了一个Sharding的Issue。刚点了根烟,就回复说新版已经修复了,希望破灭了。修复解决方案是将查询小写,好吧,就这样吧。