- 参考文档:Spring Boot入门(07):整合 MySQL 和 Druid数据源
- 参考文档:Spring Boot入门(08):如何用Spring Boot和MyBatis实现高效MySQL增删改查操作?
- 参考文档:Spring Boot入门(09):如何使用MyBatis的XML配置方式实现MySQL的增删改查操作?
- 参考文档:Spring Boot入门(10):Mybatis之XML映射文件中如何使用特殊符号?揭秘<、<=等符号的正确使用方法!
目录
数据库
本章先认识两种常用数据库,再完成 MySQL 的安装、建库建表,最后看看读取数据库的几种方式。
一、常用数据库对比
| 对比项 | SQLite | MySQL |
|---|---|---|
| 类型 | 嵌入式数据库 | 专业级数据库服务 |
| 适用场景 | 本地 / 单机使用,比如手机 App 本地存储 | 网站、后台系统、高并发业务 |
| 数据文件 | xx.db 文件,可以直接读取 |
xx.ibd 文件,不能直接读取,需要导入 |
| 本机准备 | mac 自带 sqlite | 需要安装并启动服务 |
SQLite 使用单个 .db 文件存储,复制文件即可迁移,但只适合单机场景。
MySQL 的 .ibd 文件不能直接打开:数据库中的 ibd 文件都带有身份标识,外来数据库文件无法直接识别。
所以需要先在 MySQL 中创建一个新的 yy.ibd(建库建表),再把 xx.ibd 的数据导入,才能读取。
二、MySQL 的安装与初始化
1. 安装、启动、登录与查看
## 安装 MySQL
brew install mysql
## 启动 MySQL 服务
brew services start mysql
## 设置 root 密码(重要)这里会进行一系列的初始化设置,请根据英文提示进行选择
mysql_secure_installation
## 登录mysql,输入下面指令会让输入上一步设置的密码,进行登录
mysql -u root -p
## 当看到下面这样的提示,证明已经登录成功了
╰─ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 9.6.0 Homebrew
Copyright (c) 2000, 2026, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
## 查看所有数据库
show databases;
## 退出数据库
exit;
# 停掉 MySQL
brew services stop mysql
2. 建库建表
## 创建一个数据库
create database HelloSpring;
## 使用这个数据库。看到Database changed说明现在所有的 SQL 操作,都会针对这个项目库生效。
mysql> use HelloSpring;
Database changed
mysql>
## 创建一个表
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` varchar(255) NOT NULL COMMENT '用户名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`sex` varchar(2) DEFAULT NULL COMMENT '性别',
`address` varchar(255) DEFAULT NULL COMMENT '住址',
`describes` varchar(255) DEFAULT NULL COMMENT '描述',
`image` varchar(255) DEFAULT NULL COMMENT '头像',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=60 DEFAULT CHARSET=utf8;
## 查看表
show tables;
## 查看表结构
desc user;
3. 插入测试数据
## 插入三条数据
INSERT INTO `user`(`id`, `name`, `age`, `sex`, `address`, `describes`, `image`) VALUES (1, '刘亦菲', 70, '女', '上海闵行', '这是db1的用户', './template/image/刘亦菲.jpg');
INSERT INTO `user`(`id`, `name`, `age`, `sex`, `address`, `describes`, `image`) VALUES (2, '杨幂', 20, '女', '北京朝阳', '这是db1的用户', './template/image/杨幂.jpg');
INSERT INTO `user`(`id`, `name`, `age`, `sex`, `address`, `describes`, `image`) VALUES (3, '彭于晏', 30, '男', '河北邯郸', '这是db1的用户', './template/image/彭于晏.jpg');
## 查看表内的数据
select * from user;
4. 重置 root 密码(忘记密码时使用,数据不受影响)
# 1. 停掉 MySQL
brew services stop mysql
# 2. 跳过权限校验启动(后台运行)
/opt/homebrew/opt/mysql/bin/mysqld --skip-grant-tables --skip-networking &
# 3. 免密登录并重置密码
mysql -u root <<'EOF'
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY '这里换成你的新密码';
EOF
# 4. 关掉免密实例,正常启动
kill %1
brew services start mysql
# 5. 用新密码验证
mysql -u root -p
三、数据库的读取方式
1、可视化工具:用 Navicat 等客户端连接数据库,填好地址、端口、账号密码即可读取。
2、命令行:连接 MySQL 后,通过指令和 SQL 直接读取。
3、IDEA Database:IDEA 自带的数据库工具,但可视化功能需要专业版。
4、代码读取:Spring Boot 整合 MySQL,通过代码读取数据库(下一章介绍)。
四、补充
正常的商业级开发,数据库是不会部署在本地的,一般是部署在云服务器。
后台开发者,只需要连接数据库就可以了。
Spring Boot 整合 mysql(Spring Boot 自带的 JdbcTemplate)
JDBC = Java Database Connectivity
JDBC:接口标准(契约)
数据库驱动:mysql-connector-j 是 JDBC 接口的实现(真正干活和数据库通信的)
JdbcTemplate / MyBatis / SpringDataJPA:工具 / 框架层,包装 JDBC 调用,简化开发,它们是上层封装
Spring Boot 官方提供了开箱即用的 JdbcTemplate 工具类,它对原生 JDBC 操作进行了轻量封装,大幅简化了数据库连接、语句创建、资源释放等重复样板代码的编写流程,让开发者可以专注于 SQL 本身的业务逻辑实现。
整合流程只有三步:加依赖 → 配置数据源 → 写测试验证。
前提:MySQL 服务已启动,并且已经按上一章创建好 HelloSpring 数据库和 user 表。
一、添加依赖
在 pom.xml 的 <dependencies> 中添加下面的依赖,各依赖的作用和必要性如下:
| 依赖 | 作用 | 是否必需 |
|---|---|---|
mysql-connector-j |
Java 程序与 MySQL 通信的驱动,没有它连不上数据库 它是JDBC接口规范的实现 |
必需 |
spring-boot-starter-jdbc |
提供 JdbcTemplate、连接池(默认 HikariCP)和事务管理它是上层封装,包装了JDBC的调用 |
必需 |
jakarta.annotation-api |
提供 @Resource 注解,用于注入JdbcTemplate对象 |
必需 |
lombok |
自动生成 getter/setter/toString,减少样板代码 | 强烈推荐(可选) |
mybatis-plus-boot-starter |
不写 SQL 即可完成增删改查,本章用不到,下一章详解 | 可选 |
mybatis-plus-generator、freemarker |
代码生成器及其模板引擎 | 可选 |
pom.xml 完整配置:
<dependencies>
<!--
作用:帮你自动生成 getter、setter、toString、构造方法不用手写一堆 getXXX() setXXX(),代码更干净。
必须吗? 非常推荐,几乎所有项目都用。
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!--引入jdbc stater 目的是使用JDBC模板接口-->
<!--
作用:Spring 自带的简单数据库操作工具可以用 JdbcTemplate 操作数据库。
必须吗? 你现在可以删掉!因为你用了 MyBatis-Plus,它已经包含了这个功能。
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- MySQL 驱动(新版,必须用这个) -->
<!--
作用:Java 程序和 MySQL 说话的 “翻译官”没有它,SpringBoot 根本连不上数据库。
必须吗? 必须!连数据库必用。
-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-plus-->
<!--
作用:数据库操作神器!不用写 SQL,就能实现增删改查。你现在的项目核心依赖。
必须吗? 必须!你就是用它操作 user 表。
-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!--代码生成器(可选)-->
<!--
作用 自动生成:实体类、Mapper、Service、Controller输入表名 → 一键生成全套代码。
必须吗?新手可以不用,属于辅助工具。
-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 代码生成器需要模板引擎 -->
<!--
作用:代码生成器生成代码时需要的模板。
必须吗?不用代码生成器就可以删。
-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<!--
作用:解决你最开始的报错:Cannot resolve symbol 'Resource'让你能使用 @Resource 注解注入对象。
必须吗?必须!
-->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
二、配置数据源
配置文件位于 HelloSpring/config/application.yam,每一行的作用见注释:
##jdbc:mysql:// 用 JDBC 协议连接 MySQL
#localhost 数据库在本机(你自己的电脑)
#3306 MySQL 默认端口号(固定不用改)
#HelloSpring 你要连接的数据库名字(就是你创建的那个库)
#serverTimezone=GMT%2B8 设置时区为 东八区(中国时间),必须加,否则报错
#useUnicode=true 使用 Unicode 字符集
#characterEncoding=utf-8 编码用 UTF-8,防止中文乱码
spring.datasource.url=jdbc:mysql://localhost:3306/HelloSpring?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
#MySQL 的登录用户名
spring.datasource.username=root
#MySQL 登录密码(改成你自己设置的 root 密码)
spring.datasource.password=123456
#MySQL 驱动类作用:让 Java 程序能 “听懂” MySQL 的语言
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
三、编写测试用例验证
测试类位于 src/test/java/com/lxy/hellospring/HelloSpringApplicationTests.java。
@SpringBootTest:启动完整的 Spring 容器,这样测试类里才能注入JdbcTemplate。@Resource:把容器中的JdbcTemplate注入进来。RowMapper:把结果集中的一行数据映射成一个UserEntity对象,列名要和实体字段一一对应。
package com.lxy.hellospring;
import com.lxy.hellospring.module.user.model.UserEntity;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@SpringBootTest
@Slf4j
class HelloSpringApplicationTests {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
void contextLoads() {
String sql ="select * from user";
List<UserEntity> users = jdbcTemplate.query(sql, new RowMapper<UserEntity>() {
@Override
public UserEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
UserEntity user = new UserEntity();
user.setId(rs.getInt("id"));
user.setAge(rs.getInt("age"));
user.setName(rs.getString("name"));
user.setSex(rs.getString("sex"));
user.setAddress(rs.getString("address"));
user.setDescribes(rs.getString("describes"));
user.setImage(rs.getString("image"));
return user;
}
});
log.info("查询成功");
users.forEach(p->{
log.info("用户{}",p);
});
}
}
运行测试后,控制台会输出三条用户数据,说明 Spring Boot 已经成功连上 MySQL 并完成查询:
查询成功
用户UserEntity(id=1, name=刘亦菲, age=70, sex=女, address=上海闵行, describes=这是db1的用户, image=./template/image/刘亦菲.jpg)
用户UserEntity(id=2, name=杨幂, age=20, sex=女, address=北京朝阳, describes=这是db1的用户, image=./template/image/杨幂.jpg)
用户UserEntity(id=3, name=彭于晏, age=30, sex=男, address=河北邯郸, describes=这是db1的用户, image=./template/image/彭于晏.jpg)
本章用的是 Spring Boot 自带的 JdbcTemplate:SQL 要手写,结果集要自己映射。
实际项目更常用下一章的 MyBatis,或者直接用 MyBatis-Plus,把 SQL 和映射的重复工作省掉。
Spring Boot 整合MyBatis
MyBatis 是 Java 的持久层框架,封装了 JDBC 中重复的代码(获取连接、执行 SQL、结果映射),SQL 仍然由我们自己编写。
MyBatis-Plus 是 MyBatis 的增强工具,包含了 MyBatis 的全部功能,还额外提供不用写 SQL 的增删改查。
两者只引一个即可(MyBatis-Plus 已包含 MyBatis),本章先讲原生 MyBatis。
一、添加依赖
| 依赖 | 作用 | 是否必需 |
|---|---|---|
mybatis-spring-boot-starter |
MyBatis 官方的 Spring Boot 启动器,自动创建 SqlSessionFactory 并扫描 Mapper |
必需 |
mysql-connector-j |
MySQL 驱动 | 必需 |
spring-boot-starter-jdbc |
提供数据源和事务,MyBatis starter 已间接包含 | 不用重复引 |
mybatis-spring |
把 Mapper 接口注册成 Spring Bean,starter 已包含 | 不用单独引 |
Spring Boot 3 必须使用 3.x 版本的 starter:2.x 内部依赖的是低版本 mybatis-spring,与 Spring Boot 3 冲突,启动会报错。
所以这里直接用 3.0.3,也就不需要再单独指定 mybatis-spring 的版本了。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
二、配置文件
数据库连接沿用上一章的 spring.datasource.*,再补充 MyBatis 自己的配置:
## 数据源(沿用上一章)
spring.datasource.url=jdbc:mysql://localhost:3306/HelloSpring?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
## Mapper XML 文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
## 实体类所在包,XML 里可以直接写类名
mybatis.type-aliases-package=com.lxy.hellospring.module.user.model
## 下划线转驼峰:user_name -> userName
mybatis.configuration.map-underscore-to-camel-case=true
三、编写 Mapper
1. 注解方式(SQL 简单时)
package com.lxy.hellospring.module.user.mapper;
import com.lxy.hellospring.module.user.model.UserEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface UserMapper {
@Select("select * from user")
List<UserEntity> findAll();
}
@Mapper 告诉 MyBatis:这是一个 Mapper 接口,由它生成实现类并注册到 Spring 容器。
如果 Mapper 很多,可以在启动类上写一次 @MapperScan("com.lxy.hellospring.module.user.mapper"),接口上就不用再加 @Mapper。
2. XML 方式(SQL 复杂时)
接口里只声明方法,SQL 写到 XML 中:
UserEntity findById(Integer id);
src/main/resources/mapper/UserMapper.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.lxy.hellospring.module.user.mapper.UserMapper">
<select id="findById" resultType="UserEntity">
select id, name, age, sex, address, describes, image
from user
where id = #{id}
</select>
</mapper>
注意:
namespace必须是 Mapper 接口的全限定名,id必须和方法名一致。- XML 中
<、<=等符号要转义成<、<=,或者用<![CDATA[ ... ]]>包起来,否则会解析报错。
四、测试验证
@SpringBootTest
@Slf4j
class UserMapperTests {
@Resource
private UserMapper userMapper;
@Test
void findAll() {
userMapper.findAll().forEach(p -> log.info("用户{}", p));
}
}
能打印出 user 表的三条数据,说明 MyBatis 整合成功。
五、换成 MyBatis-Plus
MyBatis-Plus 完全包含 MyBatis,把 mybatis-spring-boot-starter 换成它即可:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.16</version>
</dependency>
Mapper 接口继承 BaseMapper<UserEntity> 后,增删改查都不用写 SQL:
@Mapper
public interface UserMapper extends BaseMapper<UserEntity> {
}
注意:MyBatis-Plus 内部依赖的 mybatis-spring 版本较低时,同样会和 Spring Boot 3.x 冲突,此时额外指定 mybatis-spring 3.0.3 即可。
Spring Boot 整合Druid
一、Druid 介绍
Druid 是阿里巴巴开源的数据库连接池,可以替换 Spring Boot 默认的 HikariCP,并额外提供 SQL 监控、慢 SQL 统计、SQL 防火墙(防注入)等能力。
HikariCP 是什么?
HikariCP 是一个高性能的数据库连接池,从 Spring Boot 2 开始就是默认的连接池。
它的设计目标只有一个:把连接管理做到最快、最轻。代码量很小,没有额外的监控、审计功能,所以性能是同类里最好的。
也就是说,前面整合 MySQL、整合 MyBatis 时,项目里用的其实已经是 HikariCP 了,只是我们没有感知到。
连接池的作用:数据库连接创建和销毁都很耗时,连接池会预先建好一批连接反复复用,用完归还而不是关闭。
HikariCP 和 Druid 的区别
| 对比项 | HikariCP | Druid |
|---|---|---|
| 定位 | 纯连接池,专注性能 | 连接池 + 监控、安全中间件 |
| 性能 | 业界公认最快最轻 | 略逊于 HikariCP,业务中基本感知不到 |
| 监控 | 没有内置页面,只能看日志 | 自带 /druid 监控页,可看 SQL 执行次数、慢 SQL、连接池状态 |
| 安全 | 无 | 提供 wall 过滤器,可拦截 SQL 注入 |
| 配置 | 少量参数即可 | 参数多,功能也多 |
| 来源 | Spring Boot 2+ 默认自带 | 阿里巴巴开源,需手动引入 starter |
| 适用场景 | 大多数项目,追求简单高效 | 需要 SQL 监控、审计、防注入的后台系统 |
简单说:只要连接池就用 HikariCP,想顺便看 SQL 执行情况就用 Druid。两者选一个即可,不需要同时引入。
连接池和 ORM 互不影响:不管用 JdbcTemplate 还是 MyBatis,都可以换成 Druid。
二、添加依赖
Spring Boot 3 必须用 druid-spring-boot-3-starter,Spring Boot 2 才用 druid-spring-boot-starter:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.28</version>
</dependency>
三、配置数据源
引入 starter 后,数据源配置前缀变成 spring.datasource.druid,把上一章的 spring.datasource.* 改成下面的形式:
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.url=jdbc:mysql://localhost:3306/HelloSpring?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
## 连接池大小
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-active=20
## 获取连接的最长等待时间(毫秒)
spring.datasource.druid.max-wait=60000
## stat:监控统计;wall:防 SQL 注入
spring.datasource.druid.filters=stat,wall
四、开启监控页面
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin
启动项目后访问 http://localhost:8080/druid,用上面的账号密码登录,就能看到数据源、SQL 执行次数、慢 SQL 等统计。
生产环境要修改默认账号密码,并用 allow / deny 限制可访问的 IP。
五、验证是否生效
@SpringBootTest
@Slf4j
class DataSourceTests {
@Resource
private DataSource dataSource;
@Test
void printDataSource() {
log.info("当前数据源:{}", dataSource.getClass().getName());
}
}
控制台打印 com.alibaba.druid.pool.DruidDataSource,说明已经成功替换默认的 HikariCP。
之后正常调用 Mapper,在监控页面里就能看到对应的 SQL 记录。
Controller、Service、Mapper 分层总结
一个请求从浏览器进来,经过 Controller → Service → Mapper → 数据库,再把结果原路返回。
这几层各管一件事,职责分清楚了,代码才好维护。下面以“根据 id 查询用户”为例。
一、各层的作用
| 层 | 典型注解 | 作用 | 不该做的事 |
|---|---|---|---|
| Controller | @RestController、@RequestMapping |
接收 HTTP 请求、接收/校验参数、调用 Service、返回 JSON | 不写业务逻辑,不直接调 Mapper |
| Service(接口) | 无 | 定义业务方法,告诉调用方“能做什么” | 不写实现 |
| ServiceImpl | @Service |
实现业务逻辑:校验、组装数据、事务控制 @Transactional |
不处理 HTTP 的 request/response |
| Mapper | @Mapper |
与数据库交互,执行 SQL 并映射结果 | 不写业务判断,不调用 Service |
补充:ServiceImpl implements UserService 建立了接口和实现类的映射关系;@Service 把它注册成 Bean,Controller 注入的是接口,实际执行的是实现类。
二、一次请求的调用链
浏览器 / 前端
│ HTTP 请求:GET /user/1
▼
Controller 接收参数,决定调用哪个业务方法
│ userService.findById(1)
▼
UserService(接口)
│ 实际执行实现类
▼
UserServiceImpl 校验参数、处理业务、控制事务
│ userMapper.findById(1)
▼
UserMapper 执行 SQL
│
▼
MySQL
返回时方向相反:MySQL 的结果由 Mapper 映射成 UserEntity,交给 Service,再交给 Controller,最后由 Spring MVC 序列化成 JSON 返回给前端。
请求参数(@PathVariable、@RequestParam、@RequestBody)在 Controller 处理;SQL 只出现在 Mapper。
三、代码示例
Controller:只负责接参和返回,不写业务。
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@GetMapping("/{id}")
public UserEntity getById(@PathVariable Integer id) {
return userService.findById(id);
}
}
Service 接口:定义能力。
public interface UserService {
UserEntity findById(Integer id);
}
ServiceImpl:写业务,注入 Mapper。
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
public UserEntity findById(Integer id) {
return userMapper.findById(id);
}
}
Mapper:只和数据库打交道。
@Mapper
public interface UserMapper {
@Select("select * from user where id = #{id}")
UserEntity findById(Integer id);
// UserEntity 是数据库表 user 的映射类,包含所有字段,mybatis会根据反射完成映射
// @TableName("user")
// 注意:仅 MyBatis-Plus 内置方法(selectById/insert等)识别此注解;自定义 @Select / XML 的 SQL 不感知它
}
四、为什么要分层
- 职责单一:Controller 管 HTTP,Service 管业务,Mapper 管 SQL,出问题时容易定位。
- 便于复用:同一个 Service 可以同时给网页接口和 App 接口使用。
- 便于替换:从
JdbcTemplate换成 MyBatis、再换成 MyBatis-Plus,只需要改 Mapper,Controller 和 Service 基本不动。 - 便于测试:Service 可以脱离 Web 层单独写单元测试。
项目很小的时候,Controller 直接调 Mapper 也能跑;但业务一复杂,就会变成“接口里全是 SQL 和判断”,所以标准的写法还是这三层。
行者常至,为者常成!