Skip to content

MyBatis Spring Boot 集成

  Spring Boot 与 MyBatis 的集成通过 mybatis-spring-boot-starter 实现,自动配置了 SqlSessionFactory、SqlSessionTemplate、Mapper 扫描等,让开发者几乎零配置即可使用 MyBatis。

一、依赖与配置

1.1 Maven 依赖

xml
<!-- MyBatis Spring Boot Starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

<!-- MySQL 驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- 数据库连接池(HikariCP 默认自带) -->
<!-- Druid 连接池(可选) -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-3-starter</artifactId>
    <version>1.2.20</version>
</dependency>

1.2 application.yml 配置

yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    # HikariCP 连接池配置(默认)
    hikari:
      minimum-idle: 5
      maximum-pool-size: 20
      idle-timeout: 30000
      max-lifetime: 1800000
      connection-timeout: 30000

# MyBatis 配置
mybatis:
  # Mapper XML 文件路径
  mapper-locations: classpath:mapper/**/*.xml
  # 实体类所在包(别名)
  type-aliases-package: com.example.entity
  # 全局配置
  configuration:
    # 驼峰命名
    map-underscore-to-camel-case: true
    # 日志
    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
    # 延迟加载
    lazy-loading-enabled: true
    aggressive-lazy-loading: false
    # 缓存
    cache-enabled: true
    # 返回主键
    use-generated-keys: true

二、项目结构

src/main/java/com/example/
├── entity/
│   └── User.java              # 实体类
├── mapper/
│   └── UserMapper.java         # Mapper 接口
├── service/
│   ├── UserService.java        # 接口
│   └── impl/
│       └── UserServiceImpl.java # 实现
└── controller/
    └── UserController.java     # 控制器

src/main/resources/
├── application.yml
└── mapper/
    └── UserMapper.xml           # Mapper XML

三、代码示例

3.1 实体类

java
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Date createTime;
}

3.2 Mapper 接口

java
@Mapper  // 或者使用 @MapperScan
public interface UserMapper {
    User selectById(Long id);
    List<User> selectAll();
    int insert(User user);
    int update(User user);
    int deleteById(Long id);
}

3.3 Mapper XML

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

    <select id="selectById" resultType="User">
        SELECT * FROM user WHERE id = #{id}
    </select>

    <select id="selectAll" resultType="User">
        SELECT * FROM user
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user (name, age, email) VALUES (#{name}, #{age}, #{email})
    </insert>

    <update id="update">
        UPDATE user SET name=#{name}, age=#{age}, email=#{email} WHERE id=#{id}
    </update>

    <delete id="deleteById">
        DELETE FROM user WHERE id = #{id}
    </delete>

</mapper>

3.4 Service 层

java
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    public User createUser(User user) {
        userMapper.insert(user);
        return user;
    }

    public User findById(Long id) {
        return userMapper.selectById(id);
    }

    public List<User> findAll() {
        return userMapper.selectAll();
    }

    @Transactional
    public void updateUser(User user) {
        userMapper.update(user);
    }

    @Transactional
    public void deleteUser(Long id) {
        userMapper.deleteById(id);
    }
}

3.5 Controller 层

java
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public Result<User> getUser(@PathVariable Long id) {
        return Result.ok(userService.findById(id));
    }

    @GetMapping
    public Result<List<User>> listUsers() {
        return Result.ok(userService.findAll());
    }

    @PostMapping
    public Result<User> createUser(@RequestBody User user) {
        return Result.ok(userService.createUser(user));
    }

    @PutMapping("/{id}")
    public Result<Void> updateUser(@PathVariable Long id, @RequestBody User user) {
        user.setId(id);
        userService.updateUser(user);
        return Result.ok();
    }

    @DeleteMapping("/{id}")
    public Result<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return Result.ok();
    }
}

四、@Mapper 与 @MapperScan

java
// 方式一:每个 Mapper 接口上标注 @Mapper(不推荐,每个都要加)
@Mapper
public interface UserMapper { }

// 方式二:启动类上使用 @MapperScan(推荐,一次扫描)
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

五、事务集成

java
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private InventoryMapper inventoryMapper;

    // MyBatis 的事务由 Spring 管理
    @Transactional(rollbackFor = Exception.class)
    public void createOrder(Order order) {
        orderMapper.insert(order);  // ① 插入订单

        // ② 扣库存(如果失败,订单也会回滚)
        int rows = inventoryMapper.deductStock(order.getProductId(), order.getQuantity());
        if (rows == 0) {
            throw new RuntimeException("库存不足");
        }
    }
}

六、多数据源配置

yaml
spring:
  datasource:
    master:
      url: jdbc:mysql://localhost:3306/db_master
      username: root
      password: 123456
    slave:
      url: jdbc:mysql://localhost:3307/db_slave
      username: root
      password: 123456
java
@Configuration
@MapperScan(basePackages = "com.example.mapper.master",
            sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {

    @Primary
    @Bean(name = "masterDataSource")
    @ConfigurationProperties("spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "masterSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(
            @Qualifier("masterDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/master/**/*.xml"));
        return bean.getObject();
    }
}

七、打印 SQL 日志

yaml
# 方式一:MyBatis 配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

# 方式二:日志级别配置(推荐)
logging:
  level:
    com.example.mapper: DEBUG  # 打印 SQL

八、Spring Boot 自动配置原理

mybatis-spring-boot-starter 自动配置流程:

  ① MybatisAutoConfiguration 生效
     → 条件:存在 DataSource Bean、SqlSessionFactory 未手动创建

  ② 创建 SqlSessionFactory
     → 读取 mybatis.configuration.* 配置
     → 注册 Mapper XML(mybatis.mapper-locations)
     → 注册类型别名(mybatis.type-aliases-package)

  ③ 创建 SqlSessionTemplate
     → 线程安全的 SqlSession 实现
     → 代替 DefaultSqlSession

  ④ MapperScannerRegistrar 扫描 Mapper 接口
     → @MapperScan 指定的包或 @Mapper 标注的接口
     → 生成 MapperProxy 代理对象

九、速记总结

Spring Boot 集成 MyBatis 三步走:

  ① 加依赖:mybatis-spring-boot-starter + 数据库驱动
  ② 配文件:数据源 + mybatis.mapper-locations + 驼峰映射
  ③ 写代码:@Mapper 接口 + XML 映射 + @Service + @Controller

关键注解:
  @MapperScan  → 扫描 Mapper 接口
  @Mapper      → 标注单个 Mapper
  @Transactional → 事务管理

速记口诀:
  依赖加配置,@MapperScan 扫接口,
  XML 写 SQL,Service 加事务,Controller 调 Service。

十、面试要点

问题答案要点
@Mapper 和 @MapperScan 区别?@Mapper 单个标注,@MapperScan 批量扫描
如何配置多数据源?分别创建 DataSource、SqlSessionFactory、@MapperScan
事务怎么管理?@Transactional,Spring 管理事务
SQL 日志怎么打印?logging.level.com.xxx.mapper=DEBUG