/** * @param schema * @param ctx * @param tc * @return true表示校验通过,false表示检验不通过 */ public static boolean checkRuleRequired( SchemaConfig schema, DruidShardingParseInfo ctx, RouteCalculateUnit routeUnit, TableConfig tc) { if (!tc.isRuleRequired()) { return true; } boolean hasRequiredValue = false; String tableName = tc.getName(); if (routeUnit.getTablesAndConditions().get(tableName) == null || routeUnit.getTablesAndConditions().get(tableName).size() == 0) { hasRequiredValue = false; } else { for (Map.Entry<String, Set<ColumnRoutePair>> condition : routeUnit.getTablesAndConditions().get(tableName).entrySet()) { String colName = condition.getKey(); // 条件字段是拆分字段 if (colName.equals(tc.getPartitionColumn())) { hasRequiredValue = true; break; } } } return hasRequiredValue; }
/** * 单表路由 * * @param schema * @param ctx * @param tableName * @param rrs * @param isSelect * @return * @throws SQLNonTransientException */ public static RouteResultset tryRouteForOneTable( SchemaConfig schema, DruidShardingParseInfo ctx, RouteCalculateUnit routeUnit, String tableName, RouteResultset rrs, boolean isSelect, LayerCachePool cachePool) throws SQLNonTransientException { if (isNoSharding(schema, tableName)) { return routeToSingleNode(rrs, schema.getDataNode(), ctx.getSql()); } TableConfig tc = schema.getTables().get(tableName); if (tc == null) { String msg = "can't find table define in schema " + tableName + " schema:" + schema.getName(); LOGGER.warn(msg); throw new SQLNonTransientException(msg); } if (tc.isGlobalTable()) { // 全局表 if (isSelect) { // global select ,not cache route result rrs.setCacheAble(false); return routeToSingleNode(rrs, tc.getRandomDataNode(), ctx.getSql()); } else { // insert into 全局表的记录 return routeToMultiNode(false, rrs, tc.getDataNodes(), ctx.getSql(), true); } } else { // 单表或者分库表 if (!checkRuleRequired(schema, ctx, routeUnit, tc)) { throw new IllegalArgumentException( "route rule for table " + tc.getName() + " is required: " + ctx.getSql()); } if (tc.getPartitionColumn() == null && !tc.isSecondLevel()) { // 单表且不是childTable // return RouterUtil.routeToSingleNode(rrs, tc.getDataNodes().get(0),ctx.getSql()); return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql()); } else { // 每个表对应的路由映射 Map<String, Set<String>> tablesRouteMap = new HashMap<String, Set<String>>(); if (routeUnit.getTablesAndConditions() != null && routeUnit.getTablesAndConditions().size() > 0) { RouterUtil.findRouteWithcConditionsForTables( schema, rrs, routeUnit.getTablesAndConditions(), tablesRouteMap, ctx.getSql(), cachePool, isSelect); if (rrs.isFinishedRoute()) { return rrs; } } if (tablesRouteMap.get(tableName) == null) { return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql()); } else { // boolean isCache = rrs.isCacheAble(); // if(tablesRouteMap.get(tableName).size() > 1) { // // } return routeToMultiNode( rrs.isCacheAble(), rrs, tablesRouteMap.get(tableName), ctx.getSql()); } } } }
/** * 多表路由 * * @param schema * @param ctx * @param tables * @param rrs * @param isSelect * @return * @throws SQLNonTransientException */ public static RouteResultset tryRouteForTables( SchemaConfig schema, DruidShardingParseInfo ctx, RouteCalculateUnit routeUnit, RouteResultset rrs, boolean isSelect, LayerCachePool cachePool) throws SQLNonTransientException { List<String> tables = ctx.getTables(); if (schema.isNoSharding() || (tables.size() >= 1 && isNoSharding(schema, tables.get(0)))) { return routeToSingleNode(rrs, schema.getDataNode(), ctx.getSql()); } // 只有一个表的 if (tables.size() == 1) { return RouterUtil.tryRouteForOneTable( schema, ctx, routeUnit, tables.get(0), rrs, isSelect, cachePool); } Set<String> retNodesSet = new HashSet<String>(); // 每个表对应的路由映射 Map<String, Set<String>> tablesRouteMap = new HashMap<String, Set<String>>(); // 分库解析信息不为空 Map<String, Map<String, Set<ColumnRoutePair>>> tablesAndConditions = routeUnit.getTablesAndConditions(); if (tablesAndConditions != null && tablesAndConditions.size() > 0) { // 为分库表找路由 RouterUtil.findRouteWithcConditionsForTables( schema, rrs, tablesAndConditions, tablesRouteMap, ctx.getSql(), cachePool, isSelect); if (rrs.isFinishedRoute()) { return rrs; } } // 为全局表和单库表找路由 for (String tableName : tables) { TableConfig tableConfig = schema.getTables().get(tableName.toUpperCase()); if (tableConfig == null) { String msg = "can't find table define in schema " + tableName + " schema:" + schema.getName(); LOGGER.warn(msg); throw new SQLNonTransientException(msg); } if (tableConfig.isGlobalTable()) { // 全局表 if (tablesRouteMap.get(tableName) == null) { tablesRouteMap.put(tableName, new HashSet<String>()); } tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes()); } else if (tablesRouteMap.get(tableName) == null) { // 余下的表都是单库表 tablesRouteMap.put(tableName, new HashSet<String>()); tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes()); } } boolean isFirstAdd = true; for (Map.Entry<String, Set<String>> entry : tablesRouteMap.entrySet()) { if (entry.getValue() == null || entry.getValue().size() == 0) { throw new SQLNonTransientException("parent key can't find any valid datanode "); } else { if (isFirstAdd) { retNodesSet.addAll(entry.getValue()); isFirstAdd = false; } else { retNodesSet.retainAll(entry.getValue()); if (retNodesSet.size() == 0) { // 两个表的路由无交集 String errMsg = "invalid route in sql, multi tables found but datanode has no intersection " + " sql:" + ctx.getSql(); LOGGER.warn(errMsg); throw new SQLNonTransientException(errMsg); } } } } if (retNodesSet != null && retNodesSet.size() > 0) { if (retNodesSet.size() > 1 && isAllGlobalTable(ctx, schema)) { // mulit routes ,not cache route result if (isSelect) { rrs.setCacheAble(false); routeToSingleNode(rrs, retNodesSet.iterator().next(), ctx.getSql()); } else { // delete 删除全局表的记录 routeToMultiNode(isSelect, rrs, retNodesSet, ctx.getSql(), true); } } else { routeToMultiNode(isSelect, rrs, retNodesSet, ctx.getSql()); } } return rrs; }