{"record":{"id":"b9ca9fc9e7a1e87a","repo":"hs-web/hsweb-framework","slug":"id","errorCode":null,"errorMessage":"数据源[${id}]不存在","messagePattern":"数据源\\[(.+?)\\]不存在","errorType":"exception","errorClass":"DataSourceNotFoundException","httpStatus":null,"severity":"error","filePath":"hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/AopDataSourceSwitcherAutoConfiguration.java","lineNumber":127,"sourceCode":"                        if (strategy == null) {\n                            dataSourceChanged.set(false);\n                            logger.warn(\"strategy matcher found:{}, but strategy is null!\", matcher);\n                        } else {\n                            logger.debug(\"switch datasource. use strategy:{}\", strategy);\n                            if (strategy.isUseDefaultDataSource()) {\n                                DataSourceHolder.switcher().datasource().useDefault();\n                            } else {\n                                try {\n                                    String id = strategy.getDataSourceId();\n                                    if (StringUtils.hasText(id)) {\n                                        if (id.contains(\"${\")) {\n                                            id = ExpressionUtils.analytical(id, context.getNamedArguments(), \"spel\");\n                                        }\n                                        if (!DataSourceHolder.existing(id)) {\n                                            if (strategy.isFallbackDefault()) {\n                                                DataSourceHolder.switcher().datasource().useDefault();\n                                            } else {\n                                                throw new DataSourceNotFoundException(\"数据源[\" + id + \"]不存在\");\n                                            }\n                                        } else {\n                                            DataSourceHolder.switcher().datasource().use(id);\n                                        }\n                                        dataSourceChanged.set(true);\n                                    }\n                                } catch (RuntimeException e) {\n                                    dataSourceChanged.set(false);\n                                    throw e;\n                                } catch (Exception e) {\n                                    dataSourceChanged.set(false);\n                                    throw new RuntimeException(e.getMessage(), e);\n                                }\n                            }\n                            if (StringUtils.hasText(strategy.getDatabase())) {\n                                databaseChanged.set(true);\n                                DataSourceHolder.switcher().datasource().use(strategy.getDatabase());\n                            }","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/hs-web/hsweb-framework/blob/b2cfc85a57c70bf5b5cf6e7edae2d37102652ec8/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/AopDataSourceSwitcherAutoConfiguration.java#L109-L145","documentation":"The AOP data-source switcher intercepts a method annotated with @UseDataSource (or similar), resolves the datasource id (possibly via SpEL), and throws DataSourceNotFoundException when DataSourceHolder.existing(id) reports no such datasource and fallback-to-default is disabled.","triggerScenarios":"Annotating a service method with a datasource id string that no registered dynamic datasource provides, or an id expression (SpEL on method args) evaluating to a nonexistent datasource.","commonSituations":"Typo in @UseDataSource value; datasource not added to the dynamicDataSourceService configuration; renamed database after config change; SpEL expression pointing at an argument value that has no matching datasource.","solutions":["Correct the datasource id in the annotation/expression to match a configured datasource","Register the missing datasource in the dynamic data source service configuration","Enable fallback-to-default strategy (strategy.isFallbackDefault()) if the default source is acceptable","Log available datasource ids and compare with the requested id"],"exampleFix":"// before\n@UseDataSource(\"mysql_biz\")\npublic List<Order> listOrders() {...}\n// after\n@UseDataSource(\"mysql_business\")\npublic List<Order> listOrders() {...}","handlingStrategy":"validation","validationCode":"if (!DataSourceHolder.existing(\"mysql_business\")) {\n    throw new IllegalStateException(\"datasource mysql_business not registered\");\n}","typeGuard":"static boolean hasDataSource(String id) {\n    return DataSourceHolder.isDynamicDataSourceReady() && DataSourceHolder.existing(id);\n}","tryCatchPattern":"try {\n    return method();\n} catch (DataSourceNotFoundException e) {\n    log.error(\"datasource missing: {}\", e.getMessage());\n    DataSourceHolder.switcher().datasource().useDefault();\n    return method();\n}","preventionTips":["Verify @UseDataSource ids against configured datasources at startup","Enable fallback-to-default for non-critical paths","Test SpEL id expressions with real arguments","Keep datasource registry and annotations in sync via a startup checker"],"tags":["datasource","configuration","aop"],"backgroundTag":"resource-not-found","analyzedSha":"b2cfc85a57c70bf5b5cf6e7edae2d37102652ec8","analyzedAt":"2026-09-13T09:05:02.172Z","contentChangedAt":"2026-09-13T09:05:02.172Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}