GroupByMemoryMergedResult.getValueCaseSensitiveFromTables 空指针异常
背景
使用ShardingJDBC5.1.1版本分库分表时,服务正常启动,访问订单相关的接口,后端报空指针。访问商品相关接口没有报错。订单表配置了分片,商品表未分片,显然问题是分表插件引起的。
Caused by: java.lang.NullPointerException: null
at org.apache.shardingsphere.sharding.merge.dql.groupby.GroupByMemoryMergedResult.getValueCaseSensitiveFromTables(GroupByMemoryMergedResult.java:134)
at org.apache.shardingsphere.sharding.merge.dql.groupby.GroupByMemoryMergedResult.getValueCaseSensitive(GroupByMemoryMergedResult.java:124)
at
问题原因
order表的分片规则中,第一张物理表不存在,获取不到表元数据信息,最后导致空指针
源码分析
从数据节点中获取表元数据信息,是获取的第一个数据节点,也就是第一张order物理分片表。如果第一张物理分片表不存在,那么表的元数据信息也获取不到。
private static void addOneActualTableDataNode(final SchemaBuilderMaterials materials, final Map<String, Collection<String>> dataSourceTableGroups, final DataNodes dataNodes, final String table) {
// 获取第一个数据节点信息 .findFirst()
Optional<DataNode> optional = dataNodes.getDataNodes(table).stream().filter(dataNode -> materials.getDataSourceMap().containsKey(dataNode.getDataSourceName())).findFirst();
String dataSourceName = optional.map(DataNode::getDataSourceName).orElseGet(() -> materials.getDataSourceMap().keySet().iterator().next());
String tableName = optional.map(DataNode::getTableName).orElse(table);
addDataSourceTableGroups(dataSourceName, tableName, dataSourceTableGroups);
}
表的元数据信息没有存入到schema中,那么在查询的时候 schema.get(tableName)
返回null,最后导致空指针
private boolean getValueCaseSensitiveFromTables(final QueryResult queryResult,
final SelectStatementContext selectStatementContext, final ShardingSphereSchema schema, final int columnIndex) throws SQLException {
for (SimpleTableSegment each : selectStatementContext.getAllTables()) {
String tableName = each.getTableName().getIdentifier().getValue();
log.error("SimpleTableSegment tableName:{}", tableName);
// 根据物理表名获取表元数据信息,
TableMetaData tableMetaData = schema.get(tableName);
Map<String, ColumnMetaData> columns = tableMetaData.getColumns();
String columnName = queryResult.getMetaData().getColumnName(columnIndex);
if (columns.containsKey(columnName)) {
return columns.get(columnName).isCaseSensitive();
}
}
return false;
}
解决方法
创建第一张物理分片表即可,具体参考actual-data-nodes的配置
例如下面配置,第一张物理分片表为tb_order_202112,创建这张表,最终解决NullPointerException报错
spring:
shardingsphere:
rules:
sharding:
tables:
tb_order:
actual-data-nodes: db1.tb_order_$->{2021..2022}12,db1.tb_order_$->{2023..2100}0$->{1..9},db1.tb_order_$->{2023..2100}1$->{0..2}
如能解决问题,回来点个赞吧!