Spring 整合 MyBatis 全流程详解(附 Junit 单元测试实战)(Spring系列6)

摘要:Spring作为Java后端的核心框架,提供了强大的IoC容器来管理Bean;MyBatis是优秀的持久层框架,简化了JDBC的繁琐操作。本文从纯MyBatis开发流程入手,深入分析Spring整合MyBatis的核心思路,一步步带你完成环境搭建、配置编写、代码实现,同时补充Spring整合Junit单元测试的完整方案,附完整代码、项目结构、对比分析,帮你彻底掌握Spring整合MyBatis的原理与实践。


一、纯MyBatis开发流程回顾(环境准备)

在整合Spring之前,我们先回顾纯MyBatis的开发流程,明确MyBatis的核心对象和配置,为后续整合做铺垫。

1.1 环境搭建步骤

步骤1:准备数据库表

MyBatis用于操作数据库,首先创建数据库和表:

复制代码
create database spring_db character set utf8;
use spring_db;
create table tbl_account(
    id int primary key auto_increment,
    name varchar(35),
    money double
);

步骤2:创建项目导入Jar包(pom.xml)

复制代码
<dependencies>
    <!-- Spring核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    <!-- Druid连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.16</version>
    </dependency>
    <!-- MyBatis核心依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>

步骤3:创建模型类(domain包)

复制代码
public class Account implements Serializable {
    private Integer id;
    private String name;
    private Double money;
    // 构造器、getter、setter、toString方法略
}

步骤4:创建Dao接口

复制代码
public interface AccountDao {
    @Insert("insert into tbl_account(name,money)values(#{name},#{money})")
    void save(Account account);
    @Delete("delete from tbl_account where id = #{id} ")
    void delete(Integer id);
    @Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")
    void update(Account account);
    @Select("select * from tbl_account")
    List<Account> findAll();
    @Select("select * from tbl_account where id = #{id} ")
    Account findById(Integer id);
}

步骤5:创建Service接口和实现类

复制代码
// Service接口
public interface AccountService {
    void save(Account account);
    void delete(Integer id);
    void update(Account account);
    List<Account> findAll();
    Account findById(Integer id);
}
// Service实现类
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    @Override
    public void save(Account account) {
        accountDao.save(account);
    }
    @Override
    public void update(Account account){
        accountDao.update(account);
    }
    @Override
    public void delete(Integer id) {
        accountDao.delete(id);
    }
    @Override
    public Account findById(Integer id) {
        return accountDao.findById(id);
    }
    @Override
    public List<Account> findAll() {
        return accountDao.findAll();
    }
}

步骤6:添加jdbc.properties配置文件

复制代码
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=root

说明:useSSL=false用于关闭MySQL的SSL连接,避免警告。

步骤7:添加MyBatis核心配置文件SqlMapConfig.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3.dtd">
<configuration>
    <!-- 读取外部properties配置文件 -->
    <properties resource="jdbc.properties"></properties>
    <!-- 别名扫描的包路径 -->
    <typeAliases>
        <package name="com.itheima.domain"/>
    </typeAliases>
    <!-- 数据源 -->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 映射文件扫描包路径 -->
    <mappers>
        <package name="com.itheima.dao"/>
    </mappers>
</configuration>

步骤8:编写应用程序

复制代码
public class App {
    public static void main(String[] args) throws IOException {
        // 1. 创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 2. 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 3. 创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        // 4. 获取SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 5. 执行SqlSession对象执行查询,获取结果
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        Account ac = accountDao.findById(1);
        System.out.println(ac);
        // 6. 释放资源
        sqlSession.close();
    }
}

步骤9:运行程序

复制代码
Account{id=1, name='Tom', money=1000.0}
Process finished with exit code 0

1.2 MyBatis核心对象与整合思路分析

1.2.1 MyBatis核心对象分析

对象 作用 是否需要Spring管理
SqlSessionFactoryBuilder 构建SqlSessionFactory 无需,用完即弃
SqlSessionFactory MyBatis核心工厂,创建SqlSession ✅ 单例,需要交给Spring管理
SqlSession 会话,相当于数据库连接,获取Mapper ❌ 线程不安全,每次手动获取
Mapper接口(AccountDao) 数据层操作接口 ✅ 需要Spring扫描生成代理对象

1.2.2 整合核心思路

Spring整合MyBatis的核心就是两件事

  1. Spring管理SqlSessionFactory:将MyBatis的核心工厂交给Spring IoC容器,统一管理,避免手动创建。
  2. Spring管理Mapper接口的扫描:自动扫描Dao接口,生成代理对象,交给Spring容器,直接@Autowired注入使用。

同时,原来MyBatis配置文件SqlMapConfig.xml中的所有配置,都可以通过Spring的配置类来实现,最终可以完全舍弃该配置文件。


二、Spring整合MyBatis完整步骤

2.1 导入整合依赖

复制代码
<!-- Spring操作数据库依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
<!-- MyBatis提供的Spring整合包 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
</dependency>

说明:mybatis-spring是MyBatis官方提供的Spring整合工具包,封装了SqlSessionFactoryBean、MapperScannerConfigurer等核心类。

2.2 创建Spring主配置类

复制代码
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
}
  • @Configuration:标记该类为Spring配置类
  • @ComponentScan:组件扫描,扫描项目中的Service、Dao等Bean
  • @PropertySource:加载jdbc.properties配置文件

2.3 数据源配置类(Druid连接池)

复制代码
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
}

2.4 MyBatis核心配置类

复制代码
public class MybatisConfig {
    /**
     * 配置SqlSessionFactoryBean,生成SqlSessionFactory
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        // 设置模型类的别名扫描包
        ssfb.setTypeAliasesPackage("com.itheima.domain");
        // 设置数据源(自动注入Spring管理的DruidDataSource)
        ssfb.setDataSource(dataSource);
        return ssfb;
    }
    /**
     * 配置MapperScannerConfigurer,扫描Dao接口生成代理对象
     */
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        // 设置Dao接口的扫描包路径
        msc.setBasePackage("com.itheima.dao");
        return msc;
    }
}

重点说明:配置了MapperScannerConfigurer批量扫描dao包后,Mapper接口上无需添加@Mapper注解,即可被Spring管理并支持@Autowired注入。

1. @Mapper 注解

MyBatis 提供的注解,作用是标记当前接口为 Mapper 接口,让 Spring 能为该接口生成代理对象并注入到容器中。

2. @MapperScan / MapperScannerConfigurer

作用是批量扫描指定包下的所有接口,自动将其识别为 Mapper 接口,统一生成代理对象,无需逐个接口加注解。

3. 两者的使用关系

只要配置了批量扫描(@MapperScan / MapperScannerConfigurer),接口上就不需要再写 @Mapper;即使写了也不会报错,但属于冗余配置,没有实际作用。

4. 不同开发场景的使用规范
  • 传统 SSM 框架:使用 MapperScannerConfigurer 配置批量扫描,接口上不写 @Mapper
  • Spring Boot(主流方案):在启动类上添加 @MapperScan("xxx.dao") 配置扫描包,接口上不写 @Mapper
  • 唯一必须写 @Mapper 的场景:没有任何批量扫描配置,仅单独使用某个 Mapper 接口,这句话仅在 Spring Boot 中是可实现的。在 SSM 中不成立,因为 SSM 中即使给单个接口加 @Mapper,不配置扫描器也无法生效,不存在「不配置批量扫描就能单独用 @Mapper」的情况。
补充生效规则:
  • 纯 Spring(SSM)环境:@Mapper 必须配合 MapperScannerConfigurer 才能生效;
  • Spring Boot 环境:@Mapper 可以直接生效,因为 Spring Boot 的 MyBatis 自动配置已经帮你完成了底层扫描逻辑。

2.5 完善主配置类

复制代码
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MybatisConfig.class})
public class SpringConfig {
}

2.6 编写运行测试类

复制代码
public class App2 {
    public static void main(String[] args) {
        // 启动Spring容器
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 获取Service Bean
        AccountService accountService = ctx.getBean(AccountService.class);
        // 执行查询
        Account ac = accountService.findById(1);
        System.out.println(ac);
    }
}

2.7 项目结构说明

复制代码
spring_15_spring_mybatis
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com.itheima
│   │   │       ├── config
│   │   │       │   ├── JdbcConfig.java
│   │   │       │   ├── MybatisConfig.java
│   │   │       │   └── SpringConfig.java
│   │   │       ├── dao
│   │   │       │   └── AccountDao.java
│   │   │       ├── domain
│   │   │       │   └── Account.java
│   │   │       ├── service
│   │   │       │   ├── AccountService.java
│   │   │       │   └── impl
│   │   │       │       └── AccountServiceImpl.java
│   │   │       ├── App.java
│   │   │       └── App2.java
│   │   └── resources
│   │       └── jdbc.properties
└── pom.xml

三、Spring整合Junit单元测试

3.1 环境准备

直接使用上面整合好的Spring+MyBatis项目,在test目录下编写测试类。

3.2 整合步骤与代码实现

复制代码
步骤 1:引入依赖
在pom.xml中添加 Junit 和 Spring 测试依赖:
<!-- Junit依赖 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<!-- Spring测试依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>

步骤 2:编写测试类
在test/java/com/itheima下创建AccountServiceTest测试类:
// 设置运行器:Spring整合Junit的专用运行器
@RunWith(SpringJUnit4ClassRunner.class)
// 设置Spring配置类
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    // 自动注入Service Bean
    @Autowired
    private AccountService accountService;
    @Test
    public void testFindById(){
        System.out.println(accountService.findById(1));
    }
    @Test
    public void testFindAll(){
        System.out.println(accountService.findAll());
    }
}

关键注解说明:
@RunWith(SpringJUnit4ClassRunner.class):必须添加,Spring 提供的专用运行器,负责自动创建 Spring 容器。
@ContextConfiguration(classes = SpringConfig.class):指定 Spring 配置类,加载容器。
@Autowired:直接注入 Bean,无需手动获取。

3.3 整合vs手动方式对比

对比项 整合Spring+Junit(推荐) 不整合(手动)
容器创建 自动创建 手动new容器
Bean获取 @Autowired直接注入 getBean获取
代码简洁性 极高 冗余

手动方式代码示例(不推荐):

复制代码
public class AccountServiceTest {
    @Test
    public void testFindById() {
        // 手动创建Spring容器
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 获取Bean
        AccountService accountService = ctx.getBean(AccountService.class);
        // 执行测试
        System.out.println(accountService.findById(1));
    }
}

四、常见问题与注意事项

  1. SqlSessionFactoryBean的dataSource必须是Spring管理的,不能手动new。
  2. MapperScannerConfigurer的basePackage必须准确,否则无法生成Mapper代理对象。
  3. 配置MapperScannerConfigurer后,Mapper接口不需要@Mapper注解。
  4. @PropertySource必须加classpath:,确保配置文件加载成功。
  5. SqlSession线程不安全,不能交给Spring单例管理。
  6. 测试类中@RunWith必须在@ContextConfiguration之前。

五、总结

Spring整合MyBatis的核心思想是将MyBatis的核心对象交给Spring IoC容器统一管理,实现解耦、简化开发、统一配置:

  • 用SqlSessionFactoryBean替代SqlMapConfig.xml,管理SqlSessionFactory;
  • 用MapperScannerConfigurer自动扫描Dao接口,生成代理对象,无需@Mapper
  • 整合Junit后,自动创建容器,大幅简化单元测试。
相关推荐
胡利光11 小时前
Harness Engineering 05|Safety & HITL Harness:边界、接管与回滚
junit
Full Stack Developme11 小时前
MyBatis-Plus YAML 配置教程
mybatis
xuhaoyu_cpp_java12 小时前
MyBatis学习(五)
经验分享·笔记·学习·mybatis
user_admin_god12 小时前
SSE 流式响应 Chunk 被截断问题的排查与修复
java·人工智能·spring boot·spring·maven·mybatis
TE-茶叶蛋15 小时前
Spring最核心扩展点:BeanPostProcessor
java·后端·spring
大龄码农-涵哥15 小时前
Spring Boot项目集成AI对话:使用Spring AI打造智能客服
人工智能·spring boot·spring
Full Stack Developme15 小时前
MyBatis-Plus 注解教程
java·spring·mybatis
ffqws_16 小时前
Spring Boot 整合 PageHelper 实现分页查询
java·spring boot·mybatis
MegaDataFlowers16 小时前
常用的注解
mybatis
zhougl99616 小时前
Redis 防止丢数据
java·redis·mybatis