Spring Boot项目里MyBatis报错‘sqlSessionFactory’找不到?手把手教你排查和修复
Spring Boot与MyBatis的整合本应是开发者的"黄金搭档",但当控制台突然抛出sqlSessionFactory找不到的错误时,这种默契瞬间变成了令人头疼的谜题。这个错误看似简单,背后却可能隐藏着从依赖冲突到配置错误的层层陷阱。本文将带你深入Spring Boot的自动配置机制,用系统化的排查方法定位问题根源,并提供可立即落地的解决方案。
1. 错误背后的机制解析
当看到Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required的报错时,实际上Spring在告诉你:某个MyBatis Mapper接口尝试注入数据库操作能力时,找不到必需的"引擎"部件。要理解这个问题,我们需要拆解三个关键组件的关系:
- SqlSessionFactory:MyBatis的核心工厂类,负责创建数据库会话
- SqlSessionTemplate:Spring对MyBatis会话的包装,提供线程安全和事务集成
- Mapper接口:开发者定义的数据库操作接口,需要前两者的支持
在Spring Boot的理想世界里,只需添加mybatis-spring-boot-starter依赖,以下自动配置就会生效:
@AutoConfigureAfter(DataSourceAutoConfiguration.class) public class MybatisAutoConfiguration { @Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { // 自动创建SqlSessionFactory } }但当这个自动化流程被打断时,错误就会浮现。常见的中断点包括:
- 数据源配置缺失或错误
- MyBatis相关依赖版本不兼容
- 自动配置被意外覆盖
- 组件扫描路径设置不当
2. 系统性排查七步法
2.1 第一步:验证基础依赖
打开项目的pom.xml或build.gradle,确认存在以下核心依赖(以Spring Boot 2.7.x为例):
<dependencies> <!-- Spring Boot Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- MyBatis整合核心 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies>版本兼容性对照表:
| Spring Boot 版本 | MyBatis Starter 推荐版本 |
|---|---|
| 2.4.x | 2.1.4 |
| 2.5.x | 2.2.0 |
| 2.7.x | 2.2.2 |
| 3.0.x | 3.0.x |
提示:使用
mvn dependency:tree命令检查是否存在冲突版本,特别注意MyBatis核心包与Spring整合包的版本匹配
2.2 第二步:检查数据源配置
在application.properties或application.yml中,确保数据源配置正确:
spring: datasource: url: jdbc:mysql://localhost:3306/your_db?useSSL=false username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver验证数据源是否成功注入的一个快速方法是在启动类中添加测试代码:
@SpringBootApplication public class Application { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); DataSource dataSource = context.getBean(DataSource.class); System.out.println("DataSource配置成功: " + dataSource.getClass().getName()); } }2.3 第三步:分析启动日志
启动应用时,重点关注以下日志关键词:
DEBUG o.m.s.b.MybatisAutoConfiguration - No SqlSessionFactory configured WARN o.s.b.a.sql.init.ScriptDataSourceInitializer - No SQL scripts found完整的自动配置成功日志应包含:
Creating shared instance of singleton bean 'sqlSessionFactory' Building SqlSessionFactory from XML Parsed mapper file: file [mapper/UserMapper.xml]2.4 第四步:验证Mapper扫描配置
确保Mapper接口能被正确扫描,有以下两种方式:
注解方式:
@MapperScan("com.example.mapper") @SpringBootApplication public class Application { ... }配置方式:
mybatis.mapper-locations=classpath:mapper/*.xml mybatis.type-aliases-package=com.example.model2.5 第五步:检查手动配置冲突
如果你有自定义的SqlSessionFactory配置,确保没有破坏自动配置的条件:
@Configuration public class MyBatisConfig { // 可能覆盖自动配置的示例 @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) { // 缺少必要的配置会导致问题 return new SqlSessionFactoryBuilder().build(null); } }推荐的做法是继承MybatisAutoConfiguration:
@Configuration public class MyBatisCustomConfig extends MybatisAutoConfiguration { public MyBatisCustomConfig(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ObjectProvider<TypeHandler[]> typeHandlersProvider) { super(properties, interceptorsProvider, typeHandlersProvider); } @Override public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { // 添加自定义逻辑 return super.sqlSessionFactory(dataSource); } }2.6 第六步:调试自动配置过程
在application.properties中添加调试配置:
logging.level.org.springframework.boot.autoconfigure=DEBUG debug=true这将输出自动配置的决策过程,例如:
MybatisAutoConfiguration matched: - @ConditionalOnClass found required classes 'org.mybatis.spring.SqlSessionFactoryBean', 'javax.sql.DataSource' (OnClassCondition) - @ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) found a primary bean from beans 'dataSource' (OnBeanCondition)2.7 第七步:极端情况处理
当所有常规检查都无效时,尝试:
清理构建缓存:
mvn clean install -U检查IDE的构建路径是否包含所有资源:
# 确保src/main/resources在classpath中创建最小可复现示例,逐步添加组件
3. 典型场景解决方案
3.1 多数据源配置场景
当项目需要连接多个数据库时,自动配置会失效,需要手动定义:
@Configuration public class MultiDataSourceConfig { @Primary @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } @Primary @Bean public SqlSessionFactory primarySqlSessionFactory( @Qualifier("primaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setMapperLocations( new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/primary/*.xml")); return factory.getObject(); } @Bean public SqlSessionFactory secondarySqlSessionFactory( @Qualifier("secondaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setMapperLocations( new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/secondary/*.xml")); return factory.getObject(); } }3.2 使用HikariCP连接池优化
Spring Boot默认使用HikariCP,特殊配置如下:
spring: datasource: hikari: maximum-pool-size: 10 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 18000003.3 MyBatis-Plus整合方案
当使用MyBatis-Plus时,配置方式有所不同:
@Configuration @MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper") public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }4. 高级调试技巧
4.1 使用ConditionEvaluationReport
在启动失败时获取详细的自动配置报告:
@SpringBootApplication public class Application { public static void main(String[] args) { try { SpringApplication.run(Application.class, args); } catch (Exception e) { ConditionEvaluationReport report = ConditionEvaluationReport.get( ((ConfigurableApplicationContext) context).getBeanFactory()); report.getConditionAndOutcomesBySource().forEach((k, v) -> { System.out.println(k + " => " + v); }); } } }4.2 自定义健康检查指标
添加对MyBatis健康状态的监控:
@Component public class MyBatisHealthIndicator implements HealthIndicator { private final SqlSessionFactory sqlSessionFactory; public MyBatisHealthIndicator(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } @Override public Health health() { try (SqlSession session = sqlSessionFactory.openSession()) { session.selectOne("SELECT 1"); return Health.up().build(); } catch (Exception e) { return Health.down(e).build(); } } }4.3 动态Mapper刷新策略
开发环境下实现Mapper热加载:
@Configuration @ConditionalOnProperty(name = "mybatis.reload.enabled", havingValue = "true") public class MyBatisMapperReloadConfig { @Autowired private SqlSessionFactory sqlSessionFactory; @Bean public MapperReloader mapperReloader() { return new MapperReloader(sqlSessionFactory); } public static class MapperReloader implements ApplicationListener<ContextRefreshedEvent> { private final SqlSessionFactory sqlSessionFactory; public MapperReloader(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } @Override public void onApplicationEvent(ContextRefreshedEvent event) { Configuration configuration = sqlSessionFactory.getConfiguration(); // 清除已加载的Mapper缓存 configuration.getMapperRegistry().clearCache(); } } }