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> <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无需,用完即弃
SqlSessionFactoryMyBatis核心工厂,创建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后,自动创建容器,大幅简化单元测试。

Read more

紧急预警:微软 Edge Webview2 v144 升级导致 SAP GUI 严重白屏故障 (Note 3704912)

时间:2026 年 1 月 22 日 对于负责 SAP 运维的 Basis 团队和企业 IT 管理员而言,今天注定是忙碌的一天。大量终端用户反馈 SAP GUI 中的关键事务代码(如 SM50、SE80、RZ11)出现界面白屏、ALV 列表头部消失或按钮点击无响应的现象。 经确认,这并非 SAP 系统内核或 GUI 补丁的缺陷,而是源于微软刚刚推送的 Microsoft Edge Webview2 Runtime 最新版本 144.xxx 引入的重大 Bug。 SAP 官方已于今日紧急发布 SAP Note 3704912,确认了该组件与 SAP GUI

前端部署:别让你的应用在上线后掉链子

前端部署:别让你的应用在上线后掉链子 毒舌时刻 这部署流程写得跟绕口令似的,谁能记得住? 各位前端同行,咱们今天聊聊前端部署。别告诉我你还在手动上传文件到服务器,那感觉就像在石器时代用石头砸坚果——能用,但效率低得可怜。 为什么你需要自动化部署 最近看到一个项目,部署时需要手动复制文件到服务器,每次部署都要花上几个小时。我就想问:你是在做部署还是在做体力活? 反面教材 # 反面教材:手动部署 # 1. 构建项目 npm run build # 2. 压缩文件 zip -r build.zip build # 3. 上传到服务器 scp build.zip user@server:/var/www/html # 4. 登录服务器 ssh user@server # 5. 解压文件 unzip

FastAPI:Python 高性能 Web 框架的优雅之选

FastAPI:Python 高性能 Web 框架的优雅之选

🚀 FastAPI:Python 高性能 Web 框架的优雅之选 * 🌟 FastAPI 框架简介 * ⚡ 性能优势:为何选择 FastAPI? * 性能对比表 * 🔍 同步 vs 异步:性能测试揭秘 * 测试代码示例 * 测试结果分析 * 🛠️ FastAPI 开发体验:优雅而高效 * 1. 类型提示与自动验证 * 2. 交互式 API 文档 * 🏆 真实案例:为什么企业选择 FastAPI * 📚 后续学习引导 * 🎯 结语 🌟 FastAPI 框架简介 在当今快速发展的互联网时代,构建高效、可靠的 API 服务已成为后端开发的核心需求。FastAPI 作为 Python 生态中的新星,以其卓越的性能和开发者友好特性迅速赢得了广泛关注。 框架概述:FastAPI 是一个现代化的 Python Web 框架,专为构建

FastAPI:Python 高性能 Web 框架的优雅之选

FastAPI:Python 高性能 Web 框架的优雅之选

目录 * FastAPI:Python 高性能 Web 框架的优雅之选 * 为什么选择 FastAPI? * 实战:构建一个优雅的博客 API * 1. 环境准备 * 2. 项目结构 * 3. 定义数据模型 (models.py) * 4. 编写 API 逻辑 (main.py) * 5. 运行与体验 * 总结 专栏导读 ❤️ 欢迎各位佬关注! ❤️ 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📕 此外还有python基础专栏:请点击——>Python基础学习专栏 求订阅 🕷 此外还有爬虫专栏:请点击——>Python爬虫基础专栏 求订阅 👍 该系列文章专栏:请点击——>Python办公自动化专栏 求订阅 🏳️‍🌈 ZEEKLOG博客主页:请点击—