{"record":{"id":"bfa24eab4b1ee33f","repo":"baomidou/mybatis-plus","slug":"environment-declaration-requires-a-datasourcefacto","errorCode":null,"errorMessage":"Environment declaration requires a DataSourceFactory.","messagePattern":"Environment declaration requires a DataSourceFactory\\.","errorType":"exception","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLConfigBuilder.java","lineNumber":357,"sourceCode":"        if (context != null) {\n            String type = context.getStringAttribute(\"type\");\n            Properties props = context.getChildrenAsProperties();\n            TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance();\n            factory.setProperties(props);\n            return factory;\n        }\n        throw new BuilderException(\"Environment declaration requires a TransactionFactory.\");\n    }\n\n    private DataSourceFactory dataSourceElement(XNode context) throws Exception {\n        if (context != null) {\n            String type = context.getStringAttribute(\"type\");\n            Properties props = context.getChildrenAsProperties();\n            DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();\n            factory.setProperties(props);\n            return factory;\n        }\n        throw new BuilderException(\"Environment declaration requires a DataSourceFactory.\");\n    }\n\n    private void typeHandlersElement(XNode context) {\n        if (context == null) {\n            return;\n        }\n        for (XNode child : context.getChildren()) {\n            if (\"package\".equals(child.getName())) {\n                String typeHandlerPackage = child.getStringAttribute(\"name\");\n                typeHandlerRegistry.register(typeHandlerPackage);\n            } else {\n                String javaTypeName = child.getStringAttribute(\"javaType\");\n                String jdbcTypeName = child.getStringAttribute(\"jdbcType\");\n                String handlerTypeName = child.getStringAttribute(\"handler\");\n                Class<?> javaTypeClass = resolveClass(javaTypeName);\n                JdbcType jdbcType = resolveJdbcType(jdbcTypeName);\n                Class<?> typeHandlerClass = resolveClass(handlerTypeName);\n                if (javaTypeClass != null) {","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLConfigBuilder.java#L339-L375","documentation":"Thrown by dataSourceElement when an <environment> declaration has no <dataSource> child. Symmetric with the transactionManager check: an environment needs both a TransactionFactory and a DataSourceFactory, and a missing dataSource leaves MyBatis with no way to obtain connections, so parsing aborts.","triggerScenarios":"<environment id=\"dev\"><transactionManager type=\"JDBC\"/></environment> with the <dataSource> element missing or empty.","commonSituations":"Truncation during config templating; moving datasource definition to Spring but leaving a residual <environments> block without <dataSource>; XML merge tools dropping elements.","solutions":["Add a <dataSource type=\"POOLED\"> block with <property> entries for driver, url, username, password.","If Spring manages the DataSource, remove the whole <environments> section and build SqlSessionFactory from the Spring-managed DataSource.","Validate the XML against the MyBatis DTD to catch missing required children early."],"exampleFix":"<!-- before -->\n<environment id=\"dev\">\n  <transactionManager type=\"JDBC\"/>\n</environment>\n\n<!-- after -->\n<environment id=\"dev\">\n  <transactionManager type=\"JDBC\"/>\n  <dataSource type=\"POOLED\">\n    <property name=\"driver\" value=\"org.h2.Driver\"/>\n    <property name=\"url\" value=\"jdbc:h2:mem:test\"/>\n  </dataSource>\n</environment>","handlingStrategy":"validation","validationCode":"// ensure each <environment> has a <dataSource>\nfor (int i = 0; i < envs.getLength(); i++) {\n    org.w3c.dom.Element env = (org.w3c.dom.Element) envs.item(i);\n    if (env.getElementsByTagName(\"dataSource\").getLength() == 0)\n        throw new IllegalStateException(\"environment \" + env.getAttribute(\"id\") + \" lacks dataSource\");\n}","typeGuard":null,"tryCatchPattern":"Catch BuilderException 'Environment declaration requires a DataSourceFactory.'; add the <dataSource type=\"POOLED\"> block or remove <environments> in favor of Spring's DataSource.","preventionTips":["Keep complete <environment> templates (transactionManager + dataSource) on hand.","Validate config XML in CI."],"tags":["mybatis","mybatis-plus","xml-config","environment","datasource"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}