MyBatis 整合 Spring 完整指南:从 XML 配置到 Spring Boot 实践 MyBatis 与 Spring 的整合是企业级开发的主流方案,核心是将 MyBatis 的核心组件(SqlSessionFactory
、Mapper
代理)交给 Spring IOC 容器管理,同时复用 Spring 的事务管理、依赖注入等能力。 Spring Boot 注解式整合(主流方案) 、生产级数据源配置 、事务深化 、工程规范 及常见问题排查 ,覆盖传统 Spring 与 Spring Boot 两种场景。
版本选型与依赖优化 2024 年稳定版本组合 (支持 Spring 5 特性,兼容 JDK 8+):
传统 Spring(XML 配置)依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.16</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.1.6</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.3.31</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.3.31</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-tx</artifactId > <version > 5.3.31</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > 5.3.31</version > <scope > test</scope > </dependency > <dependency > <groupId > com.zaxxer</groupId > <artifactId > HikariCP</artifactId > <version > 5.0.1</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.33</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > <scope > test</scope > </dependency > </dependencies >
Spring Boot(注解式)依赖 Spring Boot 提供 mybatis-spring-boot-starter
,自动整合 MyBatis 与 Spring,无需手动配置 SqlSessionFactory
和 MapperScanner
,是当前主流方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <dependencies > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.7.18</version > </parent > <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 2.3.2</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-jdbc</artifactId > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <scope > runtime</scope > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
传统 Spring 整合(XML 配置)深化 1. 核心配置文件 (1)数据库配置文件(jdbc.properties
) 1 2 3 4 5 6 7 8 9 10 11 spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver spring.datasource.url =jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true spring.datasource.username =root spring.datasource.password =123456 spring.datasource.hikari.maximum-pool-size =10 # 最大连接数(根据并发调整) spring.datasource.hikari.minimum-idle =2 # 最小空闲连接数 spring.datasource.hikari.idle-timeout =300000 # 空闲连接超时时间(5分钟) spring.datasource.hikari.connection-timeout =30000 # 连接超时时间(30秒)
(2)Spring 配置文件(applicationContext.xml
) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:tx ="http://www.springframework.org/schema/tx" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" > <context:component-scan base-package ="com.zhanghe.study.mybatis.service" /> <context:property-placeholder location ="classpath:jdbc.properties" /> <bean id ="dataSource" class ="com.zaxxer.hikari.HikariDataSource" destroy-method ="close" > <property name ="driverClassName" value ="${spring.datasource.driver-class-name}" /> <property name ="jdbcUrl" value ="${spring.datasource.url}" /> <property name ="username" value ="${spring.datasource.username}" /> <property name ="password" value ="${spring.datasource.password}" /> <property name ="maximumPoolSize" value ="${spring.datasource.hikari.maximum-pool-size}" /> <property name ="minimumIdle" value ="${spring.datasource.hikari.minimum-idle}" /> <property name ="idleTimeout" value ="${spring.datasource.hikari.idle-timeout}" /> <property name ="connectionTimeout" value ="${spring.datasource.hikari.connection-timeout}" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <tx:annotation-driven transaction-manager ="transactionManager" proxy-target-class ="true" /> <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:mapper/**/*.xml" /> <property name ="configuration" > <bean class ="org.apache.ibatis.session.Configuration" > <property name ="mapUnderscoreToCamelCase" value ="true" /> <property name ="logImpl" value ="org.apache.ibatis.logging.stdout.StdOutImpl" /> <property name ="cacheEnabled" value ="true" /> </bean > </property > <property name ="typeAliasesPackage" value ="com.zhanghe.study.mybatis.model" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="com.zhanghe.study.mybatis.mapper" /> <property name ="sqlSessionFactoryBeanName" value ="sqlSessionFactory" /> </bean > </beans >
(3)简化 MyBatis 全局配置(mybatis-config.xml
) 由于大部分配置已在 SqlSessionFactoryBean
中完成,mybatis-config.xml
可简化为仅保留必要配置(如数据库厂商标识):
1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <databaseIdProvider type ="DB_VENDOR" > <property name ="MySQL" value ="mysql" /> <property name ="Oracle" value ="oracle" /> </databaseIdProvider > </configuration >
2. 事务管理深化 Spring 事务管理是整合的核心优势之一,需明确 事务传播行为 和 隔离级别 的使用场景:
(1)Service 层事务示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Service public class UserService { @Autowired private UserMapper userMapper; @Transactional public void addUserWithRole (User user, List<Integer> roleIds) { userMapper.insertUser(user); for (Integer roleId : roleIds) { userMapper.insertUserRole(user.getId(), roleId); } } @Transactional(readOnly = true, timeout = 5) public User getUserById (Integer id) { return userMapper.selectUser(id); } @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) public void logUserOperation (UserOperateLog log) { userMapper.insertOperateLog(log); } }
(2)事务关键属性说明
属性
作用
常用值
propagation
事务传播行为(如何处理嵌套事务)
REQUIRED
(默认)、REQUIRES_NEW
、SUPPORTS
isolation
事务隔离级别(解决脏读、不可重复读、幻读)
DEFAULT
(默认,跟随数据库)、READ_COMMITTED
readOnly
是否为只读事务(查询操作建议开启,优化性能)
false
(默认)、true
timeout
事务超时时间(超过时间自动回滚)
整数(秒),默认 -1
(无超时)
rollbackFor
触发回滚的异常类型(默认仅回滚运行时异常)
Exception.class
(所有异常回滚)
3. 测试类优化(Spring 测试框架) 使用 SpringJUnit4ClassRunner
自动加载 Spring 容器,避免手动创建 ApplicationContext
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.zhanghe.study.mybatis.mapper.UserMapper;import com.zhanghe.study.mybatis.model.User;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class MyBatisSpringTest { @Autowired private UserMapper userMapper; @Test public void testSelectUser () { User user = userMapper.selectUser(8 ); System.out.println(user); } }
Spring Boot 整合(注解式,主流方案) Spring Boot 通过 自动配置 简化整合,无需 XML 配置,核心是 application.yml
配置和注解扫描。
1. 核心配置文件(application.yml
) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true username: root password: 123456 hikari: maximum-pool-size: 10 minimum-idle: 2 idle-timeout: 300000 connection-timeout: 30000 mybatis: mapper-locations: classpath:mapper/**/*.xml type-aliases-package: com.zhanghe.study.mybatis.model configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl cache-enabled: true logging: level: com.zhanghe.study.mybatis.mapper: debug
2. 启动类配置(MyBatisApplication.java
) 通过 @MapperScan
扫描 Mapper 接口,替代传统 XML 中的 MapperScannerConfigurer
:
1 2 3 4 5 6 7 8 9 10 11 12 13 import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication @MapperScan("com.zhanghe.study.mybatis.mapper") public class MyBatisApplication { public static void main (String[] args) { SpringApplication.run(MyBatisApplication.class, args); } }
3. 组件实现(与传统 Spring 一致) (1)实体类(User.java
) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.zhanghe.study.mybatis.model;import java.io.Serializable;import java.util.Date;public class User implements Serializable { private Integer id; private String userName; private Integer age; private Date createTime; }
(2)Mapper 接口(UserMapper.java
) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.zhanghe.study.mybatis.mapper;import com.zhanghe.study.mybatis.model.User;import org.apache.ibatis.annotations.Param;public interface UserMapper { int insertUser (User user) ; User selectUserByUsernameAndAge (@Param("userName") String userName, @Param("age") Integer age) ; User selectUser (@Param("id") Integer id) ; }
(3)Mapper 映射文件(UserMapper.xml
) 放在 src/main/resources/mapper/
目录下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.zhanghe.study.mybatis.mapper.UserMapper" > <cache eviction ="LRU" flushInterval ="60000" size ="1024" readOnly ="false" /> <insert id ="insertUser" useGeneratedKeys ="true" keyProperty ="id" > INSERT INTO user (user_name, age, create_time) VALUES (#{userName}, #{age}, #{createTime}) </insert > <select id ="selectUserByUsernameAndAge" resultType ="User" > SELECT id, user_name, age, create_time FROM user WHERE user_name = #{userName} AND age = #{age} </select > <select id ="selectUser" resultType ="User" > SELECT id, user_name, age, create_time FROM user WHERE id = #{id} </select > </mapper >
4. 测试类(Spring Boot Test) 使用 @SpringBootTest
自动加载 Spring Boot 上下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import com.zhanghe.study.mybatis.mapper.UserMapper;import com.zhanghe.study.mybatis.model.User;import java.util.Date;@SpringBootTest public class MyBatisBootTest { @Autowired private UserMapper userMapper; @Test public void testInsertUser () { User user = new User(); user.setUserName("Spring Boot" ); user.setAge(3 ); user.setCreateTime(new Date()); int rows = userMapper.insertUser(user); System.out.println("插入行数:" + rows); System.out.println("自增主键:" + user.getId()); } @Test public void testSelectUser () { User user = userMapper.selectUser(1 ); System.out.println(user); } }
整合核心原理(简化版) 分析 SqlSessionFactoryBean
和 MapperScannerConfigurer
的源码,以下提炼核心逻辑,帮助理解整合本质:
1. SqlSessionFactoryBean
:构建 SqlSessionFactory
作用 :替代 MyBatis 原生的 SqlSessionFactoryBuilder
,将 Spring 管理的 DataSource
与 MyBatis 配置整合,生成 SqlSessionFactory
。
核心流程:
读取 dataSource
(Spring 数据源)、mapperLocations
(Mapper 映射文件)等配置;
构建 MyBatis 的 Configuration
对象(封装全局配置、Mapper 信息);
调用 SqlSessionFactoryBuilder.build(configuration)
生成 SqlSessionFactory
;
通过 FactoryBean
接口的 getObject()
方法,将 SqlSessionFactory
交给 Spring 容器。
作用 :扫描指定包下的 Mapper 接口,为每个接口生成 JDK 动态代理对象 ,并注册到 Spring 容器。
核心流程:
扫描 basePackage
下的所有接口(如 UserMapper
);
为每个接口创建 MapperFactoryBean
(实现 FactoryBean
);
MapperFactoryBean
通过 SqlSession
获取 Mapper 代理对象(sqlSession.getMapper(xxx.class)
);
Spring 容器中注入的 UserMapper
实际是 MapperFactoryBean
生成的代理对象,调用方法时底层执行 SQL。
常见问题与解决方案 1. Mapper 注入失败(No qualifying bean of type UserMapper available
)
原因 1 :未扫描 Mapper 接口(传统 Spring 未配置 MapperScannerConfigurer
,Spring Boot 未加 @MapperScan
);
原因 2 :Mapper 接口与映射文件 不同包同名 (如接口在 com.mapper
,映射文件需在 resources/com/mapper
下,且文件名一致);
解决方案:
传统 Spring:确保 MapperScannerConfigurer
的 basePackage
正确;
Spring Boot:在启动类加 @MapperScan("com.zhanghe.study.mybatis.mapper")
。
2. 事务不生效(@Transactional
注解无效)
原因 1 :未开启事务驱动(传统 Spring 未配置 <tx:annotation-driven>
,Spring Boot 需确保引入 spring-boot-starter-tx
);
原因 2 :事务方法为 非 public 修饰 (Spring 事务仅对 public 方法生效);
原因 3 :异常类型未纳入回滚(默认仅回滚 RuntimeException
,需配置 rollbackFor = Exception.class
);
解决方案:
1 2 @Transactional(rollbackFor = Exception.class) public void addUser (User user) throws Exception { ... }
3. 连接池配置无效(传统 Spring 仍用默认数据源)
原因 :依赖冲突或数据源配置错误(如 HikariCP 依赖未引入,或 jdbcUrl
拼写错误);
解决方案:
确保引入 HikariCP 依赖;
传统 Spring 中 HikariDataSource
的属性是 jdbcUrl
,而非 url
(区别于 DriverManagerDataSource
)。
4. 二级缓存不生效(跨 SqlSession 未命中)
原因 1 :实体类未实现 Serializable
(readOnly=false
时需序列化克隆对象);
原因 2 :未在 Mapper 映射文件中配置 <cache>
标签;
原因 3 :查询标签配置 useCache="false"
(禁用当前查询的二级缓存);
解决方案:
实体类实现 Serializable
;
在 UserMapper.xml
中添加 <cache/>
。
总结 MyBatis 与 Spring 整合的核心是 “Spring 管理 MyBatis 组件” ,两种方案各有适用场景:
传统 Spring(XML 配置) :适合维护旧项目,配置灵活但繁琐;
Spring Boot(注解式) :适合新项目,自动配置简化开发,是当前主流
v1.3.10