Spring整合MyBatis详解
企业级开发中,Spring(负责依赖管理和事务控制)与MyBatis(负责持久层操作)的整合是主流方案,本文我将详细讲解Spring整合MyBatis的完整流程,这种整合能充分发挥两者优势:Spring的IoC容器管理MyBatis的核心组件,AOP实现事务控制;MyBatis简化数据库操作。
一、整合优势与核心思路
1.1 整合优势
- 依赖管理自动化:Spring的IoC容器自动管理MyBatis的
SqlSessionFactory
、Mapper
等组件,无需手动创建; - 事务控制简化:通过Spring的
@Transactional
注解轻松实现事务管理,替代MyBatis手动提交事务的繁琐操作; - 配置集中化:数据库连接信息、MyBatis配置等统一在Spring配置中管理,便于维护;
- 开发效率提升:开发者专注业务逻辑,无需关注组件创建和资源释放。
1.2 核心整合思路
Spring整合MyBatis的核心是将MyBatis的核心组件交给Spring管理,关键步骤:
- Spring管理数据源(
DataSource
); - Spring创建
SqlSessionFactory
(依赖数据源和MyBatis配置); - Spring自动扫描Mapper接口,生成代理对象并注入到Service中;
- Spring管理事务(通过
DataSourceTransactionManager
)。
二、环境搭建与依赖配置
2.1 开发环境
- JDK:1.8+
- 依赖管理:Maven
- 框架版本:Spring 5.3.x + MyBatis 3.5.x
- 数据库:MySQL 8.0
2.2 Maven依赖配置
在pom.xml
中添加核心依赖(Spring核心、Spring-JDBC、MyBatis、MyBatis-Spring整合包、MySQL驱动):
<dependencies>
<!-- Spring核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<!-- Spring JDBC(数据源和事务) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.20</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- MyBatis与Spring整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 数据库连接池(HikariCP,Spring默认) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
<!-- lombok(简化POJO代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<optional>true</optional>
</dependency>
</dependencies>
三、整合配置(核心步骤)
整合配置采用注解+XML混合方式(XML配置数据源和MyBatis,注解管理Bean),清晰分离配置与业务代码。
3.1 数据库配置文件(db.properties)
创建src/main/resources/db.properties
,存储数据库连接信息:
# db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
jdbc.maxPoolSize=10
jdbc.minIdle=5
3.2 Spring配置文件(spring-mybatis.xml)
创建src/main/resources/spring-mybatis.xml
,配置数据源、SqlSessionFactory、Mapper扫描等核心组件:
<?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
https://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
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1. 扫描注解(Service、Repository等) -->
<context:component-scan base-package="com.example"/>
<!-- 2. 加载数据库配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 3. 配置数据源(HikariCP连接池) -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maximumPoolSize" value="${jdbc.maxPoolSize}"/>
<property name="minimumIdle" value="${jdbc.minIdle}"/>
</bean>
<bean id="hikariDataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 4. 配置SqlSessionFactory(MyBatis核心) -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="hikariDataSource"/> <!-- 关联数据源 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/> <!-- Mapper XML路径 -->
<property name="typeAliasesPackage" value="com.example.pojo"/> <!-- 别名包 -->
<!-- 配置MyBatis全局设置(可选) -->
<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"/> <!-- 日志 -->
</bean>
</property>
</bean>
<!-- 5. 扫描Mapper接口(生成代理对象,注入Spring容器) -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper"/> <!-- Mapper接口包路径 -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 6. 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="hikariDataSource"/>
</bean>
<!-- 7. 开启事务注解支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
四、实战案例:用户管理模块
通过一个完整的用户管理模块(CRUD操作)演示整合后的使用流程。
4.1 数据库表设计
创建user
表:
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`age` int DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.2 POJO实体类(User.java)
package com.example.pojo;
import lombok.Data;
import java.util.Date;
@Data // lombok注解,自动生成getter/setter
public class User {
private Integer id;
private String username;
private Integer age;
private Date createTime;
}
4.3 Mapper接口与XML
4.3.1 UserMapper接口
package com.example.mapper;
import com.example.pojo.User;
import java.util.List;
public interface UserMapper {
// 新增
int insert(User user);
// 更新
int update(User user);
// 删除
int deleteById(Integer id);
// 根据ID查询
User selectById(Integer id);
// 查询所有
List<User> selectAll();
}
4.3.2 UserMapper.xml(映射文件)
创建src/main/resources/mapper/UserMapper.xml
:
<?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.example.mapper.UserMapper">
<!-- 新增 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, age, create_time)
VALUES (#{username}, #{age}, #{createTime})
</insert>
<!-- 更新 -->
<update id="update">
UPDATE user
SET username = #{username}, age = #{age}
WHERE id = #{id}
</update>
<!-- 删除 -->
<delete id="deleteById">
DELETE FROM user WHERE id = #{id}
</delete>
<!-- 根据ID查询 -->
<select id="selectById" resultType="User">
SELECT id, username, age, create_time AS createTime
FROM user
WHERE id = #{id}
</select>
<!-- 查询所有 -->
<select id="selectAll" resultType="User">
SELECT id, username, age, create_time AS createTime
FROM user
</select>
</mapper>
4.4 Service层(业务逻辑)
package com.example.service;
import com.example.mapper.UserMapper;
import com.example.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Service
public class UserService {
// 注入Mapper接口(Spring自动生成代理对象)
@Autowired
private UserMapper userMapper;
// 新增用户(添加事务)
@Transactional
public int addUser(User user) {
user.setCreateTime(new Date()); // 设置创建时间
return userMapper.insert(user);
}
// 更新用户
@Transactional
public int updateUser(User user) {
return userMapper.update(user);
}
// 删除用户
@Transactional
public int deleteUser(Integer id) {
return userMapper.deleteById(id);
}
// 根据ID查询
public User getUserById(Integer id) {
return userMapper.selectById(id);
}
// 查询所有
public List<User> getAllUsers() {
return userMapper.selectAll();
}
}
4.5 测试类
package com.example.test;
import com.example.pojo.User;
import com.example.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class UserTest {
public static void main(String[] args) {
// 加载Spring配置,启动容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-mybatis.xml");
UserService userService = context.getBean(UserService.class);
// 1. 新增用户
User user = new User();
user.setUsername("Spring-MyBatis");
user.setAge(25);
userService.addUser(user);
System.out.println("新增用户ID:" + user.getId());
// 2. 查询用户
User queryUser = userService.getUserById(user.getId());
System.out.println("查询用户:" + queryUser);
// 3. 更新用户
queryUser.setAge(26);
userService.updateUser(queryUser);
System.out.println("更新后年龄:" + userService.getUserById(user.getId()).getAge());
// 4. 查询所有
List<User> users = userService.getAllUsers();
System.out.println("所有用户:" + users);
// 5. 删除用户
userService.deleteUser(user.getId());
System.out.println("删除后查询:" + userService.getUserById(user.getId()));
}
}
五、常见问题与避坑指南
5.1 Mapper注入失败(NoSuchBeanDefinitionException)
错误信息:No qualifying bean of type 'com.example.mapper.UserMapper' available
原因:
MapperScannerConfigurer
的basePackage
配置错误(未扫描到Mapper接口);- Mapper接口未定义(或包路径与配置不符);
SqlSessionFactory
未正确创建(依赖的数据源错误)。
解决方案:
- 检查
basePackage
是否正确(value="com.example.mapper"
); - 确保Mapper接口在指定包下(
com.example.mapper
); - 查看日志,确认
SqlSessionFactory
和数据源初始化成功。
5.2 事务不生效(@Transactional无效)
问题:Service方法中抛出异常,但数据库操作未回滚。
原因:
- 异常被
try-catch
捕获(未抛出到外层,Spring无法感知); - 抛出的异常不是
RuntimeException
(默认只回滚运行时异常); @Transactional
注解被添加到非public方法上(Spring事务不支持非public方法)。
解决方案:
- 不捕获异常,或捕获后重新抛出:
@Transactional
public void addUser(User user) {
try {
// 业务逻辑
} catch (Exception e) {
throw new RuntimeException(e); // 抛出运行时异常
}
}
- 若需支持checked异常,指定
rollbackFor
:
@Transactional(rollbackFor = Exception.class) // 所有异常都回滚
5.3 Mapper XML与接口不匹配
错误信息:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.mapper.UserMapper.selectById
原因:
- Mapper XML的
namespace
与接口全类名不一致; - XML中
id
与接口方法名不一致; - XML文件未被正确加载(
mapperLocations
配置错误)。
解决方案:
- 确保
namespace
正确(namespace="com.example.mapper.UserMapper"
); - 保持
id
与方法名一致(selectById
对应selectById
); - 检查
mapperLocations
配置(value="classpath:mapper/*.xml"
需与XML存放路径一致)。
总结:Spring整合MyBatis的核心要点
- 简化配置与管理:Spring的IoC容器统一管理数据源、SqlSessionFactory、Mapper等组件,无需手动创建和释放资源;
- 强大的事务支持:通过
@Transactional
注解轻松实现事务控制,替代MyBatis手动提交/回滚的繁琐操作;- 开发效率提升:开发者只需关注业务逻辑(Service)和SQL编写(Mapper),组件依赖和生命周期由Spring自动处理;
- 扩展性强:支持连接池、日志、缓存等高级特性,且易于集成其他Spring生态组件(如Spring MVC、Spring Boot)。
若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ