Spring Boot + MyBatis
Spring Boot + MyBatis
- 一、MyBatis 注解
- 1. MyBatis 是什么?
- 2. 准备环境
- 3. 创建数据库表
- 4. 新建 Spring Boot 项目依赖
- 5. 配置数据库与 MyBatis
- 6. 创建实体类
- 7. 编写 Mapper 接口
- 7.1 `@Mapper`
- 7.2 注解方式的 CRUD
- 参数绑定
- 8. 业务层 Service
- 9. 控制层 Controller
- 10. 总结
- 二、MyBatis XML
- 1. 为什么要用 XML 映射文件
- 2. 数据库表结构
- 3. Maven 依赖
- 4. Spring Boot 配置
- 5. 实体类
- 6. Mapper 接口
- 7. XML 映射文件
- MyBatis XML 文件扫描方式说明
- 方式一:通过 `mapper-locations` 配置(推荐)
- 方式二:与 Mapper 接口同路径同名(自动匹配)
- 注意事项
- 8. Service 层
- 9. Controller 层
- 10. 总结
一、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/Shanghaiusername: rootpassword: rootmybatis:type-aliases-package: com.example.demo.entityconfiguration:map-underscore-to-camel-case: true # 开启驼峰映射
-
spring.datasource 配置数据库连接信息:
-
url
:数据库地址和连接参数jdbc:mysql://
:使用 JDBC 协议连接 MySQLlocalhost
:数据库服务器地址(本机)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 {@Resourceprivate 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 {@Autowiredprivate 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/Shanghaiusername: rootpassword: rootmybatis: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.yml
或 application.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
注意事项
-
namespace
必须与 Mapper 接口全类名一致
例如:<mapper namespace="com.example.demo.mapper.UserMapper">
-
SQL 标签
<select>
、<insert>
、<update>
、<delete>
的id
必须和接口方法名一致。 -
如果不配置
mapper-locations
,但路径又没和接口保持一致,MyBatis 就找不到 XML 文件,会报错:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
这是 MyBatis Mapper XML 文件的 DOCTYPE声明,作用是告诉解析器这个 XML 文件遵循 MyBatis 3.0 的规范,帮助验证文件结构和语法正确性。
<!DOCTYPE mapperPUBLIC "-//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 mapperPUBLIC "-//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_atFROM user</select><!-- 根据 ID 查询 --><select id="findById" parameterType="int" resultType="User"><!-- parameterType 指定传入参数类型,这里是基本类型 int -->SELECT id, username, created_at, updated_atFROM userWHERE 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 userSET 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 {@Autowiredprivate 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 {@Autowiredprivate 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 代码简洁高效,开发友好