springboot3 mybatis 数据库操作入门与实战

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. 定位与理念

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

2. 核心功能对比

(1)SQL 控制能力

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

    XML 复制代码
    <select id="findByAge" resultType="User">
        SELECT * FROM user WHERE age > #{minAge} ORDER BY create_time DESC
    </select>
  • JPA :屏蔽 SQL 细节,通过 JPQL(面向对象的查询语言)Criteria API 操作数据,SQL 由框架(如 Hibernate)自动生成。例:通过 JPQL 查询:

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

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

(2)映射关系

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

    XML 复制代码
    <resultMap id="UserWithOrders" type="User">
        <id property="id" column="user_id"/>
        <collection property="orders" ofType="Order">
            <id property="id" column="order_id"/>
            <result property="amount" column="amount"/>
        </collection>
    </resultMap>
  • JPA :通过注解(@OneToOne@OneToMany 等)自动维护关联关系,框架会自动生成关联查询的 SQL。例:一对多映射:

    java 复制代码
    @Entity
    public class User {
        @Id
        private Long id;
        
        @OneToMany(mappedBy = "user") // 自动关联 Order 中的 user 字段
        private List<Order> 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. 适用场景

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

Mybatis 示例

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

Mybatis 集成

1. 添加依赖

pom.xml 中引入核心依赖:

java 复制代码
<!-- Spring Boot 父工程 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.0</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- Spring Boot Web(可选,用于接口测试) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- MyBatis 集成 Spring Boot 的 starter -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version> <!-- 适配 Spring Boot 3 -->
    </dependency>
    
    <!-- 数据库驱动(以 MySQL 为例) -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- 数据源(HikariCP,Spring Boot 3 默认) -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
    </dependency>
    
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

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. 创建实体类

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

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

4. 创建 Mapper 接口

定义数据操作方法:

java 复制代码
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<User> 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:

java 复制代码
<?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.demo.mapper.UserMapper">

    <!-- 查所有 -->
    <select id="findAll" resultType="User"> <!-- resultType 用别名(实体类名) -->
        SELECT id, username, age FROM user
    </select>
    
    <!-- 按 ID 查 -->
    <select id="findById" parameterType="Long" resultType="User">
        SELECT id, username, age FROM user WHERE id = #{id}
    </select>
    
    <!-- 新增 -->
    <insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user (username, age) VALUES (#{username}, #{age})
    </insert>
    
    <!-- 更新 -->
    <update id="update" parameterType="User">
        UPDATE user SET username = #{username}, age = #{age} WHERE id = #{id}
    </update>
    
    <!-- 删除 -->
    <delete id="deleteById" parameterType="Long">
        DELETE FROM user WHERE id = #{id}
    </delete>

</mapper>

6. 编写核心代码

java 复制代码
// 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<User> 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<User> 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. 启动类与测试

java 复制代码
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:

XML 复制代码
<select id="findByCondition" parameterType="User" resultType="User">
    SELECT * FROM user
    <where>
        <if test="username != null and username != ''">
            AND username LIKE CONCAT('%', #{username}, '%')
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>

2. 分页查询

添加依赖:

XML 复制代码
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.6</version>
</dependency>

使用方式:

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

3. 事务管理

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

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

4. 多数据源配置

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

java 复制代码
@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 配置,避免性能损耗。
相关推荐
Fency咖啡3 小时前
Spring Boot 3.x 开发 Starter 快速上手体验,通过实践理解自动装配原理
java·spring boot·后端
optimistic_chen4 小时前
【Java EE进阶 --- SpringBoot】Mybatis操作数据库(基础)
数据库·经验分享·spring boot·笔记·spring·java-ee·mybatis
Java水解4 小时前
SpringBoot 线程池 配置使用详解
spring boot·后端
TanYYF4 小时前
Spring Boot 异步处理框架核心源码解析及实现原理
java·spring boot·spring
卷Java5 小时前
uni-app 模板语法修复说明
java·数据库·spring boot·uni-app·mybatis
come112349 小时前
深入Spring Boot的核心——配置管理(指南四)
java·spring boot·后端
come112349 小时前
深入分析JAR和WAR包的区别 (指南七)
android·spring boot·后端
武昌库里写JAVA10 小时前
Java 设计模式在 Spring 框架中的实践:工厂模式与单例模式
java·vue.js·spring boot·sql·学习
千里码aicood10 小时前
springboot+vue心理健康服务小程序(源码+文档+调试+基础修改+答疑)
数据库·vue.js·spring boot