Spring框架整合MyBatis框架?(超级详细)

Spring 整合 MyBatis 详细教程(含代码解析 + 原理)

Spring 整合 MyBatis 的核心目标是:让 Spring 管理 MyBatis 的核心组件(SqlSessionFactory、Mapper 接口代理对象),简化配置(如数据源、事务),并实现依赖注入

整体流程:引入依赖 → 配置核心资源(数据源、SqlSessionFactory、Mapper 扫描) → 编写 Mapper 接口+SQL 映射 → Service 层调用 Mapper → 测试

一、环境准备:引入依赖(Maven 示例)

需引入 4 类核心依赖:Spring 核心、Spring 事务、MyBatis、MyBatis-Spring 整合包、数据库驱动(以 MySQL 8 为例)。

XML 复制代码
<dependencies>
    <!-- 1. Spring 核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.20</version> <!-- 与 Spring 其他组件版本一致 -->
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.20</version> <!-- 用于 Spring 管理数据源、事务 -->
    </dependency>

    <!-- 2. MyBatis 核心依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.10</version>
    </dependency>

    <!-- 3. MyBatis-Spring 整合包(关键!实现两者通信) -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.7</version> <!-- 需与 MyBatis、Spring 版本兼容 -->
    </dependency>

    <!-- 4. 数据库驱动(MySQL 8) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
        <scope>runtime</scope>
    </dependency>

    <!-- 5. 连接池(Spring 内置的 HikariCP,性能最优) -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>4.0.3</version>
    </dependency>

    <!-- 可选:Spring 测试、Lombok 简化代码 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.20</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
        <optional>true</optional>
    </dependency>
</dependencies>

二、核心配置:Spring 配置文件(applicationContext.xml)

核心是配置 3 个关键 Bean:数据源(DataSource)→ SqlSessionFactory → Mapper 扫描器,让 Spring 接管 MyBatis 组件。

XML 复制代码
<?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"
       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">

    <!-- 1. 开启组件扫描(扫描 @Service、@Repository 等注解) -->
    <context:component-scan base-package="com.example"/>

    <!-- 2. 配置数据源(HikariCP,Spring 推荐) -->
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <!-- MySQL 8 驱动类 -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <!-- 连接URL(useSSL=false 关闭SSL,serverTimezone指定时区) -->
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis_db?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/>
        <property name="username" value="root"/> <!-- 你的数据库用户名 -->
        <property name="password" value="123456"/> <!-- 你的数据库密码 -->
        <!-- 连接池参数(可选配置) -->
        <property name="maximumPoolSize" value="10"/> <!-- 最大连接数 -->
        <property name="minimumIdle" value="5"/> <!-- 最小空闲连接数 -->
    </bean>

    <!-- 3. 配置 SqlSessionFactory(MyBatis 核心工厂,由 Spring 管理) -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入数据源(必须,关联数据库连接) -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 配置 MyBatis 全局配置文件(可选,若有 mybatis-config.xml 则指定路径) -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- 配置 SQL 映射文件路径(Mapper.xml 文件所在位置) -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        <!-- 配置实体类别名(可选,简化 Mapper.xml 中 resultType 写法) -->
        <property name="typeAliasesPackage" value="com.example.entity"/>
    </bean>

    <!-- 4. 配置 Mapper 扫描器(关键!自动生成 Mapper 接口的代理对象) -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 注入 SqlSessionFactory(关联工厂,生成代理对象) -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 扫描 Mapper 接口所在包(会自动为该包下的接口生成代理对象) -->
        <property name="basePackage" value="com.example.mapper"/>
    </bean>

    <!-- 5. 配置事务管理器(Spring 声明式事务,可选但推荐) -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据源(事务基于数据源管理) -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 开启事务注解驱动(支持 @Transactional 注解) -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

补充:MyBatis 全局配置文件(mybatis-config.xml,可选)

用于配置 MyBatis 全局特性(如日志、驼峰命名自动转换),若无需复杂配置可省略。

XML 复制代码
<?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>
    <!-- 配置日志(可选,打印 SQL 语句方便调试) -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/> <!-- 控制台打印 SQL -->
        <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 下划线转驼峰(如 user_name → userName) -->
    </settings>
</configuration>

三、项目结构设计(规范分层)

按 "实体层 → Mapper 层 → Service 层 → 测试层" 分层,结构清晰:

复制代码
com.example
├── entity          # 实体类(与数据库表对应)
│   └── User.java
├── mapper          # Mapper 接口(MyBatis DAO 层)
│   ├── UserMapper.java  # 接口(无实现类,MyBatis 动态代理)
│   └── UserMapper.xml   # SQL 映射文件
├── service         # Service 层(业务逻辑)
│   ├── UserService.java  # 接口
│   └── impl
│       └── UserServiceImpl.java  # 实现类
├── config          # 配置文件(可选,若用注解配置)
└── test            # 测试类
    └── UserServiceTest.java

四、分层代码实现(逐步解析)

1. 实体层(Entity):与数据库表映射

假设数据库有 user 表:

sql 复制代码
CREATE TABLE `user` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `user_name` varchar(50) NOT NULL,
  `age` int NOT NULL,
  `email` varchar(100)
);

对应实体类 User.java(用 Lombok 简化 getter/setter):

java 复制代码
package com.example.entity;

import lombok.Data; // Lombok 注解,自动生成 getter/setter/toString 等

@Data // 等价于写 getter、setter、toString、equals、hashCode
public class User {
    private Integer id;       // 对应表中 id(主键)
    private String userName;  // 对应表中 user_name(驼峰命名,需开启 mapUnderscoreToCamelCase)
    private Integer age;      // 对应表中 age
    private String email;     // 对应表中 email
}

2. Mapper 层:MyBatis 数据访问层

(1)Mapper 接口(UserMapper.java)

无需写实现类,MyBatis 会通过动态代理生成代理对象(由 Spring 管理):

java 复制代码
package com.example.mapper;

import com.example.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;

// 无需加 @Repository,MapperScanner 会自动扫描并注册为 Bean
public interface UserMapper {
    // 1. 根据 ID 查询用户
    User selectById(@Param("id") Integer id); // @Param 用于指定 SQL 中参数名

    // 2. 查询所有用户
    List<User> selectAll();

    // 3. 新增用户(返回受影响行数)
    int insert(User user);

    // 4. 更新用户
    int update(User user);

    // 5. 根据 ID 删除用户
    int deleteById(@Param("id") Integer id);
}
(2)SQL 映射文件(UserMapper.xml)

放在 resources/mapper/ 目录下,与 Mapper 接口同名,绑定接口的方法:

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">

<!-- namespace 必须等于 Mapper 接口的全类名(绑定接口) -->
<mapper namespace="com.example.mapper.UserMapper">

    <!-- 1. 根据 ID 查询用户 -->
    <!-- id 必须等于接口方法名,resultType 是返回的实体类(已配置别名,直接写类名) -->
    <select id="selectById" resultType="User">
        SELECT id, user_name, age, email FROM user WHERE id = #{id}
    </select>

    <!-- 2. 查询所有用户 -->
    <select id="selectAll" resultType="User">
        SELECT id, user_name, age, email FROM user
    </select>

    <!-- 3. 新增用户 -->
    <!-- useGeneratedKeys="true" 开启主键自增,keyProperty="id" 绑定实体类的 id 属性 -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user (user_name, age, email)
        VALUES (#{userName}, #{age}, #{email})
    </insert>

    <!-- 4. 更新用户 -->
    <update id="update">
        UPDATE user
        SET user_name = #{userName}, age = #{age}, email = #{email}
        WHERE id = #{id}
    </update>

    <!-- 5. 删除用户 -->
    <delete id="deleteById">
        DELETE FROM user WHERE id = #{id}
    </delete>
</mapper>

关键解析

  • namespace:必须与 Mapper 接口全类名一致,否则 MyBatis 无法绑定接口和 SQL。
  • id:必须与接口方法名一致,MyBatis 通过 "接口全类名 + 方法名" 定位 SQL。
  • resultType:返回结果类型(已配置 typeAliasesPackage,可直接写实体类名,无需全类名)。
  • #{}:参数占位符(预编译,防止 SQL 注入),对应实体类的属性名或 @Param 指定的参数名。

3. Service 层:业务逻辑层

(1)Service 接口(UserService.java)
java 复制代码
package com.example.service;

import com.example.entity.User;
import java.util.List;

public interface UserService {
    // 根据 ID 查询用户
    User getUserById(Integer id);

    // 查询所有用户
    List<User> getAllUsers();

    // 新增用户
    boolean addUser(User user);

    // 更新用户
    boolean updateUser(User user);

    // 删除用户
    boolean deleteUser(Integer id);
}
(2)Service 实现类(UserServiceImpl.java)

通过 @Service 注册为 Spring Bean,通过 @Autowired 注入 Mapper 代理对象(Spring 已管理):

java 复制代码
package com.example.service.impl;

import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; // 事务注解
import java.util.List;

@Service // 标记为 Spring 服务层 Bean,会被 component-scan 扫描到
public class UserServiceImpl implements UserService {

    // 注入 Mapper 接口的代理对象(Spring 自动生成,无需手动创建)
    @Autowired
    private UserMapper userMapper;

    @Override
    public User getUserById(Integer id) {
        // 直接调用 Mapper 方法(代理对象会自动执行 SQL)
        return userMapper.selectById(id);
    }

    @Override
    public List<User> getAllUsers() {
        return userMapper.selectAll();
    }

    @Override
    @Transactional // 标记该方法需要事务(失败时回滚)
    public boolean addUser(User user) {
        // 调用 Mapper 新增方法,返回受影响行数(>0 表示成功)
        int rows = userMapper.insert(user);
        return rows > 0;
    }

    @Override
    @Transactional
    public boolean updateUser(User user) {
        int rows = userMapper.update(user);
        return rows > 0;
    }

    @Override
    @Transactional
    public boolean deleteUser(Integer id) {
        int rows = userMapper.deleteById(id);
        return rows > 0;
    }
}

关键解析

  • @Service:告诉 Spring 这是服务层 Bean,Spring 会自动创建实例并管理。
  • @Autowired:依赖注入 Mapper 代理对象(Spring 通过 MapperScanner 扫描后,将代理对象注册到容器,此处直接注入即可使用)。
  • @Transactional:声明式事务注解,标记该方法需要事务支持(如新增 / 更新 / 删除操作,失败时自动回滚,避免数据不一致)。

五、测试:验证整合结果

使用 Spring Test 测试 Service 层,验证 MyBatis 是否正常工作。

java 复制代码
package com.example.test;

import com.example.entity.User;
import com.example.service.UserService;
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 java.util.List;

// 1. 运行器:使用 SpringJUnit4ClassRunner 整合 JUnit 和 Spring
@RunWith(SpringJUnit4ClassRunner.class)
// 2. 加载 Spring 配置文件(指定 applicationContext.xml 路径)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserServiceTest {

    // 注入 Service Bean(Spring 容器已创建)
    @Autowired
    private UserService userService;

    // 测试查询所有用户
    @Test
    public void testGetAllUsers() {
        List<User> users = userService.getAllUsers();
        users.forEach(System.out::println); // 打印用户列表
    }

    // 测试新增用户
    @Test
    public void testAddUser() {
        User user = new User();
        user.setUserName("张三");
        user.setAge(25);
        user.setEmail("zhangsan@example.com");
        boolean success = userService.addUser(user);
        System.out.println("新增是否成功:" + success);
        System.out.println("新增用户 ID:" + user.getId()); // 主键自增后,id 会被回写到实体类
    }

    // 测试根据 ID 查询
    @Test
    public void testGetUserById() {
        User user = userService.getUserById(1); // 假设新增的用户 ID 为 1
        System.out.println("查询到的用户:" + user);
    }
}

六、核心原理解析(为什么这样整合?)

  1. SqlSessionFactoryBean :MyBatis-Spring 提供的工厂 Bean,负责创建 SqlSessionFactory(MyBatis 核心工厂),并关联 Spring 管理的数据源,避免手动创建 SqlSessionFactory 的繁琐。
  2. MapperScannerConfigurer :扫描指定包下的 Mapper 接口,为每个接口生成 SqlSession 管理的代理对象,并将代理对象注册到 Spring 容器,后续可通过 @Autowired 直接注入。
  3. 事务管理 :Spring 的 DataSourceTransactionManager 接管事务,通过 @Transactional 注解实现声明式事务,无需手动管理 SqlSession 的提交 / 回滚。
  4. 依赖注入:Spring 统一管理数据源、SqlSessionFactory、Mapper 代理对象、Service Bean,实现各层之间的解耦,无需手动创建对象。

七、常见问题排查

  1. Mapper 接口注入失败(No qualifying bean of type)
    • 检查 MapperScannerConfigurerbasePackage 是否正确(需包含 Mapper 接口包)。
    • 确保 Mapper 接口没有写实现类(MyBatis 动态代理不需要)。
  2. SQL 映射文件找不到(BindingException)
    • 检查 SqlSessionFactoryBeanmapperLocations 路径是否正确(如 classpath:mapper/*.xml)。
    • 确保 UserMapper.xmlnamespace 与 Mapper 接口全类名一致。
  3. 数据库连接失败(SQLException)
    • 检查数据源的 jdbcUrlusernamepassword 是否正确。
    • MySQL 8 需用 com.mysql.cj.jdbc.Driver 驱动,且指定 serverTimezone
  4. 驼峰命名不生效(如 user_name 无法映射到 userName)
    • mybatis-config.xml 中开启 mapUnderscoreToCamelCase 配置。

八、扩展:注解式 SQL(无需 Mapper.xml)

若不想写 XML 文件,可使用 MyBatis 注解直接在 Mapper 接口上写 SQL,简化配置:

java 复制代码
package com.example.mapper;

import com.example.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;

public interface UserMapper {
    @Select("SELECT id, user_name, age, email FROM user WHERE id = #{id}")
    User selectById(@Param("id") Integer id);

    @Select("SELECT id, user_name, age, email FROM user")
    List<User> selectAll();

    @Insert("INSERT INTO user (user_name, age, email) VALUES (#{userName}, #{age}, #{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id") // 主键自增配置
    int insert(User user);

    @Update("UPDATE user SET user_name = #{userName}, age = #{age}, email = #{email} WHERE id = #{id}")
    int update(User user);

    @Delete("DELETE FROM user WHERE id = #{id}")
    int deleteById(@Param("id") Integer id);
}

此时可删除 Mapper.xml 文件,同时删除 SqlSessionFactoryBeanmapperLocations 配置。

相关推荐
summer__777740 分钟前
38-第七章:集合(7.1-7.4)
java
低头不见42 分钟前
CTE聚合查询,性能优化不止10几倍
java·sql·postgresql
踏浪无痕1 小时前
你真的懂泛型吗?手写 MyBatis-Plus + Jackson,揭秘框架设计的精髓
后端·json·mybatis
老青蛙1 小时前
Easy Work-简单、易用、傻瓜式的 Java 流程引擎
java·开源
茶杯6751 小时前
“舒欣双免“方案助力MSI-H/dMMR结肠癌治疗新突破
java·服务器·前端
我真会写代码1 小时前
从入门到精通:Java Socket 网络编程实战(含线程池优化)
java·linux·服务器·socket·tcp/ip协议
BBB努力学习程序设计1 小时前
Java:理解数据类型和变量
java
亭上秋和景清1 小时前
数据在内存中的存储
java·开发语言
古城小栈1 小时前
SpringBoot:声明式事务 和 编程式事务 的擂台霸业
java·spring boot·后端