跳到主要内容
Spring 整合 MyBatis 全流程详解及 JUnit 单元测试 | 极客日志
Java java
Spring 整合 MyBatis 全流程详解及 JUnit 单元测试 Spring 整合 MyBatis 的完整流程。首先回顾纯 MyBatis 开发环境,明确核心对象如 SqlSessionFactory 和 Mapper 接口。接着讲解如何通过 Spring 配置类替代 XML 文件,利用 SqlSessionFactoryBean 管理工厂,使用 MapperScannerConfigurer 批量扫描 Mapper 接口。最后提供基于 SpringJUnit4ClassRunner 的 JUnit 单元测试方案,对比自动注入与手动获取容器的差异,并总结常见配置注意事项,帮助开发者实现解耦与高效开发。
莫名其妙 发布于 2026/4/6 更新于 2026/5/20 30 浏览一、纯 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 >
<dependency >
<groupId > org.springframework</groupId >
<artifactId > spring-context</artifactId >
<version > 5.2.10.RELEASE</version >
</dependency >
<dependency >
<groupId > com.alibaba</groupId >
<artifactId > druid</artifactId >
<version > 1.1.16</version >
</dependency >
org.mybatis
mybatis
3.5.6
mysql
mysql-connector-java
5.1.47
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
<version >
</version >
</dependency >
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
<version >
</version >
</dependency >
</dependencies >
步骤 3:创建模型类(domain 包) public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
}
步骤 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 接口和实现类
public interface AccountService {
void save (Account account) ;
void delete (Integer id) ;
void update (Account account) ;
List<Account> findAll () ;
Account findById (Integer id) ;
}
@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 resource ="jdbc.properties" > </properties >
<typeAliases >
<package name ="com.itheima.domain" />
</typeAliases >
<environments default ="mysql" >
<environment >
<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 {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder ();
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml" );
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
Account ac = accountDao.findById(1 );
System.out.println(ac);
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 的核心就是两件事 :
Spring 管理 SqlSessionFactory :将 MyBatis 的核心工厂交给 Spring IoC 容器,统一管理,避免手动创建。
Spring 管理 Mapper 接口的扫描 :自动扫描 Dao 接口,生成代理对象,交给 Spring 容器,直接@Autowired 注入使用。
同时,原来 MyBatis 配置文件 SqlMapConfig.xml 中的所有配置,都可以通过 Spring 的配置类来实现,最终可以完全舍弃该配置文件。
二、Spring 整合 MyBatis 完整步骤
2.1 导入整合依赖
<dependency >
<groupId > org.springframework</groupId >
<artifactId > spring-jdbc</artifactId >
<version > 5.2.10.RELEASE</version >
</dependency >
<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 {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean (DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean ();
ssfb.setTypeAliasesPackage("com.itheima.domain" );
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer () {
MapperScannerConfigurer msc = new MapperScannerConfigurer ();
msc.setBasePackage("com.itheima.dao" );
return msc;
}
}
重点说明:配置了 MapperScannerConfigurer 批量扫描 dao 包后,Mapper 接口上无需添加@Mapper 注解,即可被 Spring 管理并支持@Autowired 注入。
@Mapper 注解 MyBatis 提供的注解,作用是标记当前接口为 Mapper 接口,让 Spring 能为该接口生成代理对象并注入到容器中。
@MapperScan / MapperScannerConfigurer 作用是批量扫描指定包下的所有接口,自动将其识别为 Mapper 接口,统一生成代理对象,无需逐个接口加注解。
两者的使用关系 只要配置了批量扫描(@MapperScan / MapperScannerConfigurer),接口上就不需要再写 @Mapper ;即使写了也不会报错,但属于冗余配置,没有实际作用。
不同开发场景的使用规范
传统 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) {
ApplicationContext ctx = new AnnotationConfigApplicationContext (SpringConfig.class);
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 测试依赖:
<dependency >
<groupId > junit</groupId >
<artifactId > junit</artifactId >
<version > 4.12</version >
<scope > test</scope >
</dependency >
<dependency >
<groupId > org.springframework</groupId >
<artifactId > spring-test</artifactId >
<version > 5.2.10.RELEASE</version >
</dependency >
步骤 2:编写测试类 在 test/java/com/itheima 下创建 AccountServiceTest 测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@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 () {
ApplicationContext ctx = new AnnotationConfigApplicationContext (SpringConfig.class);
AccountService accountService = ctx.getBean(AccountService.class);
System.out.println(accountService.findById(1 ));
}
}
四、常见问题与注意事项
SqlSessionFactoryBean 的 dataSource 必须是 Spring 管理的,不能手动 new。
MapperScannerConfigurer 的 basePackage 必须准确,否则无法生成 Mapper 代理对象。
配置 MapperScannerConfigurer 后,Mapper 接口不需要 @Mapper 注解。
@PropertySource 必须加 classpath:,确保配置文件加载成功。
SqlSession 线程不安全,不能交给 Spring 单例管理。
测试类中@RunWith 必须在@ContextConfiguration 之前。
五、总结 Spring 整合 MyBatis 的核心思想是将 MyBatis 的核心对象交给 Spring IoC 容器统一管理 ,实现解耦、简化开发、统一配置:
用 SqlSessionFactoryBean 替代 SqlMapConfig.xml,管理 SqlSessionFactory;
用 MapperScannerConfigurer 自动扫描 Dao 接口,生成代理对象,无需@Mapper ;
整合 Junit 后,自动创建容器,大幅简化单元测试。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online