public Optional<RouteContext> loadRouteContext(final OriginSQLRouter originSQLRouter, final QueryContext queryContext, final RuleMetaData globalRuleMetaData,
                                                   final ShardingSphereDatabase database, final ShardingCache shardingCache, final ConfigurationProperties props,
                                                   final ConnectionContext connectionContext) {
        if (queryContext.getSql().length() > shardingCache.getConfiguration().getAllowedMaxSqlLength()) {
            return Optional.empty();
        }
        ShardingRouteCacheableCheckResult cacheableCheckResult = shardingCache.getRouteCacheableChecker().check(database, queryContext);
        if (!cacheableCheckResult.isProbablyCacheable()) {
            return Optional.empty();
        }
        List<Object> shardingConditionParams = new ArrayList<>(cacheableCheckResult.getShardingConditionParameterMarkerIndexes().size());
        for (int each : cacheableCheckResult.getShardingConditionParameterMarkerIndexes()) {
            if (each >= queryContext.getParameters().size()) {
                return Optional.empty();
            }
            shardingConditionParams.add(queryContext.getParameters().get(each));
        }
        Optional<RouteContext> cachedResult = shardingCache.getRouteCache().get(new ShardingRouteCacheKey(queryContext.getSql(), shardingConditionParams))
                .flatMap(ShardingRouteCacheValue::getCachedRouteContext);
        RouteContext result = cachedResult.orElseGet(
                () -> originSQLRouter.createRouteContext(queryContext, globalRuleMetaData, database, shardingCache.getShardingRule(), props, connectionContext));
        if (!cachedResult.isPresent() && hitOneShardOnly(result)) {
            shardingCache.getRouteCache().put(new ShardingRouteCacheKey(queryContext.getSql(), shardingConditionParams), new ShardingRouteCacheValue(result));
        }
        return Optional.of(result);
    }
@Test
    void assertCreateRouteContextWithCacheableQueryButCacheMissed() {
        QueryContext queryContext =
                new QueryContext(sqlStatementContext, "insert into t values (?, ?)", Arrays.asList(0, 1), new HintValueContext(), mockConnectionContext(), mock(ShardingSphereMetaData.class));
        when(shardingCache.getConfiguration()).thenReturn(new ShardingCacheConfiguration(100, null));
        when(shardingCache.getRouteCacheableChecker()).thenReturn(mock(ShardingRouteCacheableChecker.class));
        when(shardingCache.getRouteCacheableChecker().check(null, queryContext)).thenReturn(new ShardingRouteCacheableCheckResult(true, Collections.singletonList(1)));
        when(shardingCache.getRouteCache()).thenReturn(mock(ShardingRouteCache.class));
        RouteContext expected = new RouteContext();
        expected.getRouteUnits().add(new RouteUnit(new RouteMapper("ds_0", "ds_0"), Collections.singletonList(new RouteMapper("t", "t"))));
        expected.getOriginalDataNodes().add(Collections.singletonList(new DataNode("ds_0", "t")));
        when(shardingCache.getRouteCache().get(any(ShardingRouteCacheKey.class))).thenReturn(Optional.empty());
        OriginSQLRouter router = (unused, globalRuleMetaData, database, rule, props, connectionContext) -> expected;
        Optional<RouteContext> actual = new CachedShardingSQLRouter().loadRouteContext(router, queryContext, mock(RuleMetaData.class), null, shardingCache, null, null);
        assertTrue(actual.isPresent());
        assertThat(actual.get(), is(expected));
        verify(shardingCache.getRouteCache()).put(any(ShardingRouteCacheKey.class), any(ShardingRouteCacheValue.class));
    }