Spring Boot与MyBatis深度整合实战指南

1. 项目初始化与环境准备

在开始Spring Boot与MyBatis的整合之前,我们需要确保开发环境已经准备就绪。首先创建一个基础的Spring Boot项目,推荐使用Spring Initializr(https://start.spring.io/)进行快速初始化。在选择依赖时,务必勾选以下核心模块:

  • Spring Web :用于构建Web应用的基础支持
  • MyBatis Framework :MyBatis的Spring Boot官方starter
  • MySQL Driver 或其他数据库驱动:根据实际使用的数据库选择

初始化完成后,项目结构应该包含以下关键目录:

src/main/java
  └─com.example.demo
      ├─config       # 自定义配置类
      ├─controller   # Web层
      ├─service      # 业务逻辑层
      ├─mapper       # 数据访问层接口
      └─entity       # 实体类
src/main/resources
  ├─static
  ├─templates
  └─application.yml  # 主配置文件

2. 基础配置详解

2.1 数据源配置

在application.yml中配置数据源是整合的第一步。Spring Boot提供了简洁的配置方式:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
    username: root
    password: yourpassword
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 15
      minimum-idle: 5
      connection-timeout: 30000

提示:生产环境中密码应该使用加密配置,推荐使用Jasypt等工具进行敏感信息加密

2.2 MyBatis基础配置

在application.yml中添加MyBatis相关配置:

mybatis:
  mapper-locations: classpath:mapper/*.xml  # XML映射文件位置
  type-aliases-package: com.example.demo.entity  # 实体类包路径
  configuration:
    map-underscore-to-camel-case: true  # 自动驼峰命名转换
    default-fetch-size: 100
    default-statement-timeout: 30

2.3 XML映射与接口绑定

MyBatis的核心特性之一就是接口与XML的绑定。创建一个简单的用户查询示例:

  1. 首先定义实体类:
package com.example.demo.entity;

public class User {
    private Long id;
    private String username;
    private String email;
    // getters and setters
}
  1. 创建Mapper接口:
package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {
    User selectById(Long id);
}
  1. 编写对应的XML映射文件(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.demo.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="User">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="email" property="email" />
    </resultMap>
    
    <select id="selectById" resultMap="BaseResultMap">
        SELECT * FROM user WHERE id = #{id}
    </select>
</mapper>

3. 高级特性配置

3.1 缓存机制详解

MyBatis提供了一级缓存和二级缓存机制,合理使用可以显著提升性能。

一级缓存 (默认开启):

  • 作用域:SqlSession级别
  • 特点:同一个SqlSession中相同的查询会直接返回缓存结果
  • 失效条件:执行增删改操作、调用clearCache()、关闭SqlSession

二级缓存配置 : 在application.yml中开启二级缓存:

mybatis:
  configuration:
    cache-enabled: true

在Mapper接口上添加注解:

@CacheNamespace
public interface UserMapper {
    // 方法定义
}

或者在XML映射文件中配置:

<mapper namespace="com.example.demo.mapper.UserMapper">
    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
    <!-- 其他配置 -->
</mapper>

3.2 动态SQL实践

MyBatis强大的动态SQL能力可以让我们灵活构建查询条件。以下是几个常用场景:

条件查询示例

<select id="selectUsers" resultMap="BaseResultMap">
    SELECT * FROM user
    <where>
        <if test="username != null">
            AND username LIKE CONCAT('%', #{username}, '%')
        </if>
        <if test="email != null">
            AND email = #{email}
        </if>
        <if test="statusList != null and statusList.size() > 0">
            AND status IN
            <foreach collection="statusList" item="status" open="(" separator="," close=")">
                #{status}
            </foreach>
        </if>
    </where>
    ORDER BY create_time DESC
</select>

更新语句示例

<update id="updateSelective" parameterType="User">
    UPDATE user
    <set>
        <if test="username != null">username = #{username},</if>
        <if test="email != null">email = #{email},</if>
    </set>
    WHERE id = #{id}
</update>

4. 性能优化与最佳实践

4.1 分页查询实现

MyBatis与Spring Boot整合时,推荐使用PageHelper实现物理分页:

  1. 添加依赖:
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>最新版本</version>
</dependency>
  1. 在application.yml中配置:
pagehelper:
  helper-dialect: mysql
  reasonable: true
  support-methods-arguments: true
  1. 使用示例:
public PageInfo<User> getUsers(int pageNum, int pageSize) {
    PageHelper.startPage(pageNum, pageSize);
    List<User> users = userMapper.selectAll();
    return new PageInfo<>(users);
}

4.2 批量操作优化

对于批量插入或更新操作,MyBatis提供了高效的实现方式:

批量插入示例

@Insert("<script>" +
        "INSERT INTO user (username, email) VALUES " +
        "<foreach collection='list' item='item' separator=','>" +
        "(#{item.username}, #{item.email})" +
        "</foreach>" +
        "</script>")
void batchInsert(List<User> users);

批量更新示例

<update id="batchUpdate">
    <foreach collection="list" item="item" separator=";">
        UPDATE user 
        SET username = #{item.username}, email = #{item.email}
        WHERE id = #{item.id}
    </foreach>
</update>

注意:批量操作时需要考虑数据库对SQL语句长度的限制,建议每批处理100-1000条数据

4.3 复杂查询结果映射

对于一对多、多对多等复杂关系,MyBatis提供了强大的结果映射能力:

<resultMap id="UserWithOrdersMap" type="User" extends="BaseResultMap">
    <collection property="orders" ofType="Order">
        <id column="order_id" property="id"/>
        <result column="order_no" property="orderNo"/>
        <result column="order_amount" property="amount"/>
    </collection>
</resultMap>

<select id="selectUserWithOrders" resultMap="UserWithOrdersMap">
    SELECT 
        u.*, 
        o.id as order_id, 
        o.order_no, 
        o.amount as order_amount
    FROM user u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = #{id}
</select>

5. 常见问题排查

5.1 配置不生效问题

当发现配置没有按预期生效时,可以按照以下步骤排查:

  1. 检查配置文件的加载顺序和优先级
  2. 确认没有在多个位置重复配置相互冲突的属性
  3. 检查依赖版本是否兼容
  4. 查看启动日志中的自动配置报告

5.2 SQL注入防范

虽然MyBatis的#{}语法已经可以防止大部分SQL注入,但仍需注意:

  • 永远不要使用${}拼接用户输入的参数
  • 对于like查询,应该在Java代码中处理通配符,而不是在SQL中
  • 定期检查Mapper中的SQL语句安全性

5.3 事务管理

Spring Boot中整合MyBatis的事务管理非常简单:

@Service
@Transactional
public class UserService {
    private final UserMapper userMapper;
    
    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
    
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) {
        userMapper.update(user);
        // 其他数据库操作
    }
}

关键点:

  • 使用@Transactional注解声明事务
  • 默认只对RuntimeException回滚,可通过rollbackFor指定其他异常类型
  • 事务方法应该放在Service层,而不是Controller层
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐