Mybatis 项目

https://gitee.com/supervol/loong-springboot-study

(记得给个start,感谢)

Mybatis 概述

        在 Spring Boot 3 环境中,MyBatis 作为一款轻量级持久层框架,凭借其对 SQL 的灵活控制和与 Spring 生态的良好兼容性,成为数据访问层的常用选择。

Mybatis 核心

        MyBatis 专注于解决 JDBC 操作的痛点(如手动处理连接、结果集映射等),同时保留开发者对 SQL 的直接控制权,核心特性包括:

  • SQL 与代码解耦:通过 XML 或注解定义 SQL,避免硬编码;
  • 灵活的映射机制:支持对象与数据库表的自动映射(如下划线转驼峰),也可手动配置复杂映射(一对一、一对多关联);
  • 动态 SQL:通过标签(ifchooseforeach 等)根据条件动态生成 SQL,简化复杂查询;
  • 轻量级:无侵入性,核心依赖少,性能接近原生 JDBC;
  • 与 Spring 无缝集成:通过 mybatis-spring-boot-starter 快速整合到 Spring Boot 3 中,无需手动管理 SqlSession 等组件。

Mybatis 对比

        MyBatis 和 JPA(Java Persistence API)是 Java 生态中最常用的两种持久层技术,它们的设计理念和适用场景有显著差异。

1. 定位与理念

维度MyBatisJPA
定位半自动 ORM 框架(SQL 与对象映射分离)ORM 规范(通常指 Hibernate 等实现,全自动 ORM)
设计理念聚焦 SQL 控制,保留开发者对 SQL 的直接管理权聚焦对象模型,通过面向对象的方式操作数据库
核心目标简化 JDBC 操作,同时不丢失 SQL 的灵活性消除 SQL 依赖,让开发者以 "操作对象" 的方式操作数据库

2. 核心功能对比

(1)SQL 控制能力

  • MyBatis:完全开放 SQL 控制权,支持 手写 SQL(XML 或注解),开发者可直接编写优化后的原生 SQL、存储过程、复杂联合查询等。例:通过 XML 或 @Select 注解直接定义 SQL:

  • JPA:屏蔽 SQL 细节,通过 JPQL(面向对象的查询语言) 或 Criteria API 操作数据,SQL 由框架(如 Hibernate)自动生成。例:通过 JPQL 查询:

    @Query("SELECT u FROM User u WHERE u.age > :minAge ORDER BY u.createTime DESC")
    List findByAgeGreaterThan(@Param("minAge") int minAge);

    复杂场景下也可手写原生 SQL,但违背 JPA "屏蔽 SQL" 的设计初衷。

(2)映射关系

  • MyBatis:需手动配置 结果映射(ResultMap) 处理对象关联(一对一、一对多等),灵活性高但配置繁琐。例:一对多映射:

    
        
        
            
            
        
    
  • JPA:通过注解(@OneToOne@OneToMany 等)自动维护关联关系,框架会自动生成关联查询的 SQL。例:一对多映射:

    @Entity
    public class User {
        @Id
        private Long id;
        @OneToMany(mappedBy = "user") // 自动关联 Order 中的 user 字段
        private List orders;
    }

(3)开发效率

  • MyBatis

    • 简单 CRUD 需手动编写 SQL(或通过代码生成工具生成),开发速度较慢;
    • 复杂查询时,手写 SQL 反而更高效(避免框架生成冗余 SQL)。
  • JPA

    • 基于 Spring Data JPA 时,通过继承 JpaRepository 可直接获得 CRUD、分页、排序等功能,无需编写实现;
    • 例:public interface UserRepository extends JpaRepository<User, Long> 即可直接调用 findAll()save() 等方法;
    • 简单业务场景下开发效率极高,复杂场景需额外配置(如自定义 JPQL)。

(4)性能与优化

  • MyBatis

    • 性能接近原生 JDBC,因为 SQL 可控,可针对性优化(如索引利用、查询字段精简);
    • 无额外缓存(需手动集成 Redis 等),但避免了框架级缓存的复杂性。
  • JPA(以 Hibernate 为例)

    • 自动生成的 SQL 可能存在冗余(如关联查询过度加载),需通过 fetch = FetchType.LAZY 等配置优化;
    • 内置一级缓存(Session 级)和二级缓存(全局),可减少重复查询,但缓存配置不当易引发数据一致性问题。

(5)学习曲线

  • MyBatis:门槛低,对熟悉 SQL 的开发者友好,核心只需掌握 Mapper 接口、XML 映射规则即可。

  • JPA:门槛较高,需理解 ORM 核心概念(如持久化上下文、脏检查)、JPQL 语法、关联映射策略等,初期学习成本高。

3. 适用场景

框架适用场景不适用场景
MyBatis1. 需精细控制 SQL(如复杂报表、多表联合查询);2. 数据库设计不规范(字段名与对象属性差异大);3. 团队熟悉 SQL 优化;4. 对性能要求极高的场景。1. 快速开发简单 CRUD 业务;2. 团队更擅长面向对象编程而非 SQL。
JPA1. 业务简单(以 CRUD 为主),需快速迭代;2. 数据库设计规范,适合 ORM 映射;3. 团队偏好面向对象编程,希望减少 SQL 编写。1. 复杂 SQL 场景(如多表嵌套查询、存储过程);2. 需深度优化 SQL 性能的场景。

Mybatis 示例

        请参考项目地址中 springboot-orm/springboot-mybatis 模块代码。

Mybatis 集成

1. 添加依赖

        在 pom.xml 中引入核心依赖:



    org.springframework.boot
    spring-boot-starter-parent
    3.2.0
    


    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
    
        org.mybatis.spring.boot
        mybatis-spring-boot-starter
        3.0.3 
    
    
    
        com.mysql
        mysql-connector-j
        runtime
    
    
    
        com.zaxxer
        HikariCP
    
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

2. 核心配置

        在 src/main/resources/application.yaml 中配置:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    username: root
    password: 123456
    hikari: # HikariCP 配置
      maximum-pool-size: 10 # 最大连接数
      minimum-idle: 5 # 最小空闲连接
mybatis:
  mapper-locations: classpath:mybatis/mappers/*.xml # Mapper XML 文件位置
  type-aliases-package: com.example.demo.entity # 实体类别名包(简化 XML 中的类名)
  configuration:
    map-underscore-to-camel-case: true # 开启下划线转驼峰(如数据库字段 user_name → 实体类 userName)
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 日志(开发环境用)

3. 创建实体类

package com.example.demo.entity;
public class User {
    private Long id;
    private String username; // 对应数据库 user_name(下划线转驼峰生效)
    private Integer age;
    // 省略 getter、setter、toString
}

4. 创建 Mapper 接口

        定义数据操作方法:

package com.example.demo.mapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
// @Mapper 标识为 MyBatis 映射接口(或在启动类用 @MapperScan 批量扫描)
@Mapper
public interface UserMapper {
    // 查询所有用户
    List findAll();
    // 根据 ID 查询
    User findById(Long id);
    // 新增用户
    int insert(User user);
    // 更新用户
    int update(User user);
    // 删除用户
    int deleteById(Long id);
}

5. 编写 Mapper XML

        在 src/main/resources/mybatis/mappers/UserMapper.xml 中编写 SQL:





    
    
    
    
    
    
        INSERT INTO user (username, age) VALUES (#{username}, #{age})
    
    
    
        UPDATE user SET username = #{username}, age = #{age} WHERE id = #{id}
    
    
    
        DELETE FROM user WHERE id = #{id}
    

6. 编写核心代码

// Service 层(业务逻辑)
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
    private final UserMapper userMapper;
    // 构造器注入(Spring Boot 3 推荐)
    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
    public List getAllUsers() {
        return userMapper.findAll();
    }
    public User getUserById(Long id) {
        return userMapper.findById(id);
    }
    public void addUser(User user) {
        userMapper.insert(user);
    }
}
// Controller 层(接口暴露)
package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;
    public UserController(UserService userService) {
        this.userService = userService;
    }
    @GetMapping
    public List getAll() {
        return userService.getAllUsers();
    }
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    @PostMapping
    public String add(@RequestBody User user) {
        userService.addUser(user);
        return "新增成功,ID:" + user.getId();
    }
}

7. 启动类与测试

package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// @MapperScan 批量扫描 Mapper 接口(替代每个接口加 @Mapper)
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

启动后,访问 http://localhost:8080/users 即可测试接口。

Mybatis 高级

1. 动态 SQL

        通过 <if>、<choose>、<foreach> 等标签动态生成 SQL:

2. 分页查询

        添加依赖:


    com.github.pagehelper
    pagehelper-spring-boot-starter
    1.4.6

        使用方式:

// Service 中
public PageInfo getUsersByPage(int pageNum, int pageSize) {
    PageHelper.startPage(pageNum, pageSize); // 分页拦截
    List users = userMapper.findAll();
    return new PageInfo<>(users); // 封装分页信息
}

3. 事务管理

        通过 Spring 的 @Transactional 注解控制事务:

@Service
public class UserService {
    // ...
    @Transactional // 方法内所有操作要么全成功,要么全回滚
    public void batchAdd(List users) {
        for (User user : users) {
            userMapper.insert(user);
        }
    }
}

4. 多数据源配置

        通过 @Configuration 配置多个数据源,配合 @MapperScan 指定不同 Mapper 对应的数据源:

@Configuration
public class DataSourceConfig {
    @Primary // 默认数据源
    @Bean
    @ConfigurationProperties("spring.datasource.first")
    public DataSource firstDataSource() {
        return DataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties("spring.datasource.second")
    public DataSource secondDataSource() {
        return DataSourceBuilder.create().build();
    }
}

Mybatis 注意

  1. 版本兼容性:MyBatis-Spring-Boot-Starter 需使用 3.x 版本(适配 Spring Boot 3);
  2. 包名迁移:Spring Boot 3 基于 Jakarta EE,若使用 javax.persistence 相关注解,需替换为 jakarta.persistence
  3. Mapper 扫描:确保 @Mapper 或 @MapperScan 正确配置,否则会出现 "No qualifying bean" 错误;
  4. SQL 日志:生产环境建议关闭 log-impl 配置,避免性能损耗。

posted on 2025-09-30 10:56  lxjshuju  阅读(20)  评论(0)    收藏  举报