Java IllegalArgumentException: Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required问题解决

'# Java IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required问题解决

一、背景与问题

在基于Spring Boot的MyBatis项目中,开发人员常常会遇到以下异常:

java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

这个错误通常出现在以下场景中:

  1. 在Spring Boot项目中未正确配置MyBatis
  2. 在XML配置文件中遗漏了关键属性
  3. 在使用注解配置时未正确声明Bean
  4. 在多数据源环境中配置错误

这个问题的根源在于Spring和MyBatis的整合机制中,SqlSessionFactory和SqlSessionTemplate作为核心组件,其创建过程需要依赖特定的配置参数。当这些参数未被正确提供时,Spring会抛出上述异常。

二、基本原理

MyBatis与Spring的整合本质上是通过BeanPostProcessor实现的。当Spring容器启动时,会通过以下流程处理MyBatis配置:

  1. 读取配置文件中的MyBatis配置
  2. 创建SqlSessionFactory(通过SqlSessionFactoryBean)
  3. 创建SqlSessionTemplate(通过SqlSessionTemplate)
  4. 注入到Mapper接口中

关键点在于:

  • SqlSessionFactory需要配置dataSource、mapperLocations等属性
  • SqlSessionTemplate需要配置sqlSessionFactory和executorType等属性
  • 这些配置参数必须通过Spring的配置机制传递

三、环境准备

我们使用Spring Boot 2.7 + MyBatis 2.2.2的环境:

<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <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>
        <version>8.0.29</version>
    </dependency>
</dependencies>

四、核心实现

1. XML配置方式

@Configuration
public class MyBatisConfig {
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/*.xml"));
        return factory.getObject();
    }
    
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

关键点:

  • 必须显式声明这两个Bean
  • 需要通过setter方法传递参数
  • 需要处理异常

2. 注解配置方式

@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/*.xml"));
        return factory.getObject();
    }
}

3. Spring Boot自动配置

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  mybatis:
    mapper-locations: classpath*:mapper/*.xml

五、完整案例

创建一个完整的Spring Boot项目:

  1. 实体类:

    @Entity
    public class User {
     @Id
     private Long id;
     private String name;
     // getters and setters
    }
  2. Mapper接口:

    @Mapper
    public interface UserMapper {
     User selectById(Long id);
    }
  3. 配置类:

    @Configuration
    @MapperScan("com.example.mapper")
    public class MyBatisConfig {
     @Bean
     public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
         SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
         factory.setDataSource(dataSource);
         factory.setMapperLocations(new PathMatchingResourcePatternResolver()
                 .getResources("classpath*:mapper/*.xml"));
         return factory.getObject();
     }
    }
  4. 启动类:

    @SpringBootApplication
    public class Application {
     public static void main(String[] args) {
         SpringApplication.run(Application.class, args);
     }
    }

完整案例说明:

  • 使用@MapperScan自动注册Mapper接口
  • 通过SqlSessionFactoryBean创建SqlSessionFactory
  • 自动注入到Mapper接口中
  • 无需显式声明SqlSessionTemplate

六、源码解析

在Spring Boot的自动配置中,关键代码如下:

@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionTemplate.class})
@ConditionalOnMissingBean({SqlSessionFactory.class, SqlSessionTemplate.class})
public class MyBatisAutoConfiguration {
    // 自动配置逻辑
}

关键点:

  • 通过@ConditionalOnClass确保依赖存在
  • 通过@ConditionalOnMissingBean确保未显式配置时自动创建
  • 使用BeanPostProcessor进行后处理

七、进阶使用

多数据源配置

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public DataSource routingDataSource(DataSource primary, DataSource secondary) {
        AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("primary", primary);
        targetDataSources.put("secondary", secondary);
        routingDataSource.setDefaultTargetDataSource(primary);
        routingDataSource.setTargetDataSources(targetDataSources);
        return routingDataSource;
    }
}

自定义SqlSessionFactory

@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setConfiguration(new Configuration());
    factory.setMapperLocations(new PathMatchingResourcePatternResolver()
            .getResources("classpath*:mapper/*.xml"));
    return factory.getObject();
}

八、性能与工程实践

性能优化建议

  1. 使用连接池配置:

    spring:
      datasource:
     url: jdbc:mysql://localhost:3306/mydb
     username: root
     password: password
     driver-class-name: com.mysql.cj.jdbc.Driver
     hikari:
       maximum-pool-size: 20
  2. 启用MyBatis缓存:

    <cache></cache>
  3. 避免频繁创建SqlSessionTemplate

安全注意事项

  1. 配置文件中避免直接暴露敏感信息
  2. 使用加密配置项(如Vault)
  3. 避免将数据库密码硬编码在代码中

九、常见问题与踩坑

1. 配置遗漏

// 错误示例
@Bean
public SqlSessionFactory sqlSessionFactory() {
    return new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
}

问题:未指定DataSource,导致创建的SqlSessionFactory无效

2. 版本兼容性问题

// 错误示例
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    return factory.getObject();
}

问题:MyBatis 3.5+版本需要显式设置mapperLocations

3. 多数据源配置错误

// 错误示例
@Bean
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}

问题:未配置多数据源时,会创建单一数据源

十、最佳实践

推荐方案

  1. 使用Spring Boot自动配置(推荐)
  2. 在需要自定义配置时使用@MapperScan
  3. 对于多数据源场景,使用AbstractRoutingDataSource
  4. 使用HikariCP作为连接池
  5. 对于复杂配置,使用XML文件管理

避免使用的情况

  1. 不需要自定义配置时,不要显式声明Bean
  2. 不要在单数据源场景中使用复杂的配置
  3. 避免在配置中硬编码敏感信息

十一、总结

Java的IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required问题本质上是Spring与MyBatis整合过程中的配置问题。通过深入理解其工作原理,我们可以更有效地进行配置管理。

在实际开发中,建议:

  • 使用Spring Boot的自动配置简化配置
  • 在需要自定义配置时,使用@MapperScan和SqlSessionFactoryBean
  • 对于多数据源场景,使用AbstractRoutingDataSource
  • 始终保持配置的简洁性和可维护性

通过合理配置和深入理解底层原理,可以有效避免这类问题,同时提升系统的稳定性和可维护性。在复杂的业务场景中,正确的配置是保证系统正常运行的关键基础。

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日