Spring Boot + MyBatis

发布于:2025-08-17 ⋅ 阅读:(19) ⋅ 点赞:(0)

一、MyBatis 注解

1. MyBatis 是什么?

MyBatis 是一款优秀的 持久层框架,作用是:

  • 将 SQL 从 Java 代码中分离,写在 XML 或注解中,便于维护。
  • 自动将 SQL 查询结果映射为 Java 对象。
  • 支持动态 SQL、分页、缓存等功能。

相比 JPA(Hibernate),MyBatis 更灵活,SQL 可控性强,适合对性能和 SQL 结构有要求的项目。


2. 准备环境

技术栈:

  • JDK 17(JDK 8 以上均可)
  • Spring Boot 3.x
  • MyBatis-Spring-Boot-Starter
  • MySQL 8.x
  • Maven

3. 创建数据库表

user 表为例:

CREATE DATABASE mybatis_demo DEFAULT CHARSET utf8mb4;

USE mybatis_demo;

CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updataed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

注意:updataed_at 是保持与你的字段名一致,实际中推荐使用 updated_at


4. 新建 Spring Boot 项目依赖

pom.xml 添加如下依赖:

<dependencies>
    <!-- MyBatis -->
    <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>
        <version>8.3.0</version>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.28</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

5. 配置数据库与 MyBatis

好的,帮你把简短的 URL 各部分说明加到你的配置说明里,整合如下:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_demo?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root

mybatis:
  type-aliases-package: com.example.demo.entity
  configuration:
    map-underscore-to-camel-case: true  # 开启驼峰映射
  • spring.datasource 配置数据库连接信息:

    • url:数据库地址和连接参数

      • jdbc:mysql://:使用 JDBC 协议连接 MySQL
      • localhost:数据库服务器地址(本机)
      • 3306:MySQL 默认端口号
      • mybatis_demo:连接的数据库名
      • characterEncoding=utf8:设置字符编码为 UTF-8,防止乱码
      • useSSL=false:关闭 SSL 连接
      • serverTimezone=Asia/Shanghai:设置时区为上海,避免时间偏差
    • username:数据库用户名

    • password:数据库密码

  • mybatis.type-aliases-package
    指定实体类所在包,MyBatis 自动为包内类生成别名,简化 SQL 映射配置。

  • mybatis.configuration.map-underscore-to-camel-case
    开启数据库字段下划线到 Java 驼峰命名的自动映射,如 created_at 自动映射为 createdAt,减少手动配置。

6. 创建实体类

@Data 来自 Lombok,自动生成 getter/setter、toString、equals、hashCode 等,减少样板代码。

package com.example.demo.entity;

import lombok.Data;
import java.time.LocalDateTime;

@Data
public class User {
    private Integer id;
    private String username;
    private LocalDateTime createdAt;
    private LocalDateTime updataedAt; // 保持与数据库字段名一致
}

7. 编写 Mapper 接口

7.1 @Mapper

标记接口为 MyBatis Mapper,Spring Boot 自动扫描并生成代理。

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;

@Mapper
public interface UserMapper {
    @Select("SELECT id, username FROM user")
    List<User> findAll();
}

7.2 注解方式的 CRUD

  • @Select:查询,返回实体或集合
  • @Insert:插入,参数为对象,返回受影响行数
  • @Update:更新,返回受影响行数
  • @Delete:删除,返回受影响行数

参数绑定

  • 使用 #{参数名} 绑定方法参数或对象属性
  • 基础类型参数直接绑定变量名,对象参数绑定属性名

示例:

@Mapper
public interface UserMapper {
    @Select("SELECT id, username FROM user")
    List<User> findAll();

    @Select("SELECT id, username FROM user WHERE id = #{id}")
    User findById(int id);

    @Insert("INSERT INTO user (username) VALUES (#{username})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);

    @Update("UPDATE user SET username=#{username} WHERE id=#{id}")
    int update(User user);

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

@Options(useGeneratedKeys = true, keyProperty = "id") 会将数据库自动生成的主键回写到 User 实体的 id 字段。


8. 业务层 Service

封装调用 Mapper,方便扩展业务逻辑:

package com.example.demo.service;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserService {

    @Resource
    private UserMapper userMapper;

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

    public User getUserById(int id) {
        return userMapper.findById(id);
    }

    public int addUser(User user) {
        return userMapper.insert(user);
    }

    public int updateUser(User user) {
        return userMapper.update(user);
    }

    public int deleteUser(int id) {
        return userMapper.delete(id);
    }
}

9. 控制层 Controller

接收 HTTP 请求,调用 Service,返回 JSON 结果或操作提示。

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/t")
public class TetsController {

    @Autowired
    private UserService userService;

    @GetMapping("/getAllUsers")
    public List<User> getAllUsers() {
        log.info("请求获取所有用户");
        return userService.getAllUsers();
    }

    @GetMapping("/getUserById/{id}")
    public User getUserById(@PathVariable int id) {
        log.info("请求获取用户,id={}", id);
        return userService.getUserById(id);
    }

    @PostMapping("/addUser")
    public String addUser(@RequestBody User user) {
        log.info("请求添加用户: {}", user);
        int result = userService.addUser(user);
        return result > 0 ? "添加用户成功" : "添加用户失败";
    }

    @PutMapping("/updateUser")
    public String updateUser(@RequestBody User user) {
        log.info("请求更新用户: {}", user);
        int result = userService.updateUser(user);
        return result > 0 ? "更新用户成功" : "更新用户失败";
    }

    @DeleteMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable int id) {
        log.info("请求删除用户,id={}", id);
        int result = userService.deleteUser(id);
        return result > 0 ? "删除用户成功" : "删除用户失败";
    }
}

10. 总结

  • 使用 @Mapper 注解标记 Mapper 接口,简化开发流程。
  • 注解方式定义 SQL,免去 XML 配置,开发更快捷。
  • 通过 @Options 实现主键自动回写,方便获取插入记录的 ID。
  • 业务层封装 Mapper 操作,易于扩展。
  • 控制层处理 HTTP 请求,结合日志打印,便于调试和维护。

二、MyBatis XML

1. 为什么要用 XML 映射文件

虽然注解方式简单,但对于以下情况,XML 方式更适合:

  • SQL 较复杂(多表关联、动态 SQL、分页)。
  • 需要维护大量 SQL,集中管理更方便。
  • 便于 DBA 直接修改 SQL,不影响 Java 代码。

2. 数据库表结构

使用前面教程的 user 表:

CREATE DATABASE mybatis_demo DEFAULT CHARSET utf8mb4;

USE mybatis_demo;

CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

(这里我把 updataed_at 改成了 updated_at


3. Maven 依赖

pom.xml 跟注解版相同:

<dependencies>
    <!-- MyBatis -->
    <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>
        <version>8.3.0</version>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.28</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

4. Spring Boot 配置

application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_demo?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root

mybatis:
  type-aliases-package: com.example.demo.entity  # 别名包
  mapper-locations: classpath:mapper/*.xml       # XML 文件位置
  configuration:
    map-underscore-to-camel-case: true           # 下划线转驼峰

5. 实体类

com/example/demo/entity/User.java

package com.example.demo.entity;

import lombok.Data;
import java.time.LocalDateTime;

@Data
public class User {
    private Integer id;
    private String username;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

6. Mapper 接口

com/example/demo/mapper/UserMapper.java

package com.example.demo.mapper;

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

import java.util.List;

@Mapper
public interface UserMapper {
    List<User> findAll();
    User findById(int id);
    int insert(User user);
    int update(User user);
    int delete(int id);
}

7. XML 映射文件

MyBatis XML 文件扫描方式说明

MyBatis 在运行时需要加载 .xml 映射文件(Mapper XML),常用的两种方式如下:


方式一:通过 mapper-locations 配置(推荐)

application.ymlapplication.properties 中显式指定扫描路径:

mybatis:
  mapper-locations: classpath:mapper/*.xml
  • classpath: 表示 src/main/resources/ 下的路径。
  • mapper/*.xml 表示扫描 resources/mapper/ 目录下的所有 .xml 文件。
  • 优点:XML 文件集中管理在 mapper 目录,结构清晰。

路径结构示例:

src
 ├─ main
 │   ├─ java
 │   │    └─ com/example/demo/mapper/UserMapper.java
 │   └─ resources
 │        └─ mapper/UserMapper.xml

方式二:与 Mapper 接口同路径同名(自动匹配)

  • .xml 文件放在与 Mapper 接口 相同的包路径下,并与接口同名。
  • MyBatis 会根据 Mapper 接口的全类名自动去匹配对应的 XML 文件。
  • 优点:不需要在 application.yml 里配置 mapper-locations

路径结构示例:

src
 ├─ main
 │   ├─ java
 │   │    └─ com/example/demo/mapper/UserMapper.java
 │   └─ resources
 │        └─ com/example/demo/mapper/UserMapper.xml

注意事项

  1. namespace 必须与 Mapper 接口全类名一致
    例如:

    <mapper namespace="com.example.demo.mapper.UserMapper">
    
  2. SQL 标签 <select><insert><update><delete>id 必须和接口方法名一致。

  3. 如果不配置 mapper-locations,但路径又没和接口保持一致,MyBatis 就找不到 XML 文件,会报错:

    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
    

这是 MyBatis Mapper XML 文件的 DOCTYPE声明,作用是告诉解析器这个 XML 文件遵循 MyBatis 3.0 的规范,帮助验证文件结构和语法正确性。

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
  • mapper 是根元素名
  • 指定了官方托管的 DTD 文件地址
  • 有助于IDE校验和智能提示

src/main/resources/mapper/UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.demo.mapper.UserMapper">
    <!-- namespace 指定当前 XML 映射文件对应的 Mapper 接口的全限定名,
         MyBatis 根据它来绑定接口方法和 XML 语句 -->

    <!-- 查询全部 -->
    <select id="findAll" resultType="User">
        <!-- id 是方法名,MyBatis 会绑定接口 UserMapper 的 findAll() 方法调用此 SQL -->
        <!-- resultType 指定返回的 Java 类型,这里返回 User 实体类 -->
        SELECT id, username, created_at, updated_at
        FROM user
    </select>

    <!-- 根据 ID 查询 -->
    <select id="findById" parameterType="int" resultType="User">
        <!-- parameterType 指定传入参数类型,这里是基本类型 int -->
        SELECT id, username, created_at, updated_at
        FROM user
        WHERE id = #{id}
        <!-- #{id} 是参数占位符,MyBatis 会将接口方法参数传入此处 -->
    </select>

    <!-- 插入用户 -->
    <insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        <!-- useGeneratedKeys = true 表示使用 JDBC 的 getGeneratedKeys 方法自动获取数据库生成的主键 -->
        <!-- keyProperty = "id" 指定将主键回写到 User 对象的 id 属性 -->
        INSERT INTO user (username)
        VALUES (#{username})
    </insert>

    <!-- 更新用户 -->
    <update id="update" parameterType="User">
        UPDATE user
        SET username = #{username}
        WHERE id = #{id}
    </update>

    <!-- 删除用户 -->
    <delete id="delete" parameterType="int">
        DELETE FROM user WHERE id = #{id}
    </delete>

</mapper>

8. Service 层

跟注解版一致:

package com.example.demo.service;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

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

    public User getUserById(int id) {
        return userMapper.findById(id);
    }

    public int addUser(User user) {
        return userMapper.insert(user);
    }

    public int updateUser(User user) {
        return userMapper.update(user);
    }

    public int deleteUser(int id) {
        return userMapper.delete(id);
    }
}

9. Controller 层

跟注解版一致:

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/t")
public class TestController {

    @Autowired
    private UserService userService;

    @GetMapping("/getAllUsers")
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @GetMapping("/getUserById/{id}")
    public User getUserById(@PathVariable int id) {
        return userService.getUserById(id);
    }

    @PostMapping("/addUser")
    public String addUser(@RequestBody User user) {
        int result = userService.addUser(user);
		return result > 0 ? "添加用户成功" : "添加用户失败";
	}

	
	@PutMapping("/updateUser")
	public String updateUser(@RequestBody User user) {
	    int result = userService.updateUser(user);
	    return result > 0 ? "更新用户成功" : "更新用户失败";
	}
	
	@DeleteMapping("/deleteUser/{id}")
	public String deleteUser(@PathVariable int id) {
	    int result = userService.deleteUser(id);
	    return result > 0 ? "删除用户成功" : "删除用户失败";
	}
}

10. 总结

  • XML 文件方式更适合复杂的 SQL 管理和动态 SQL
  • 通过 mapper-locations 配置扫描 XML 文件更灵活,结构清晰
  • XML 中 namespace 和接口必须严格对应
  • SQL 语句写法标准,可复用性好,便于维护
  • 注解方式适合简单场景,XML 方式适合复杂业务
  • 配合 Spring Boot,MyBatis 代码简洁高效,开发友好

网站公告

今日签到

点亮在社区的每一天
去签到