一、数据库 — MySQL
作用
存数据的地方,比如用户信息、订单、商品等。
在 Spring Boot 中怎么用
1) 引入依赖(pom.xml)
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2) 配置连接(application.yml)
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
关键知识点
| JDBC | Java 连接数据库的标准接口,所有框架底层都是它 |
| 连接池 | HikariCP(Spring Boot 默认),不用每次创建连接,复用连接提高性能 |
| 事务 | 一组操作要么全成功,要么全回滚(比如转账:扣A的钱 + 加B的钱) |
二、ORM — MyBatis / JPA
作用
不用手写 JDBC 那一套繁琐代码,用更简单的方式操作数据库。
两者对比
| SQL | 自己写 SQL,灵活 | 自动生成 SQL,省事 |
| 学习成本 | 低,会 SQL 就行 | 中,要学 JPQL / 方法命名规则 |
| 适合场景 | 复杂查询多 | 简单增删改查为主 |
| 国内流行度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
MyBatis 核心用法
// 1. 写一个 Mapper 接口
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Long id);
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
void insert(User user);
}
// 2. 在 Service 里直接用
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User getUser(Long id) {
return userMapper.findById(id);
}
}
JPA 核心用法
// 1. 定义实体类(和数据库表对应)
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
}
// 2. 写 Repository(继承一个接口就搞定)
public interface UserRepository extends JpaRepository<User, Long> {
// 按方法名自动生成 SQL
List<User> findByName(String name);
List<User> findByAgeGreaterThan(Integer age);
}
// 3. Service 里直接用
@Autowired
private UserRepository userRepository;
userRepository.findById(1L); // 查
userRepository.save(new User()); // 增/改
userRepository.deleteById(1L); // 删
关键知识点
| #{id} vs ${id} | MyBatis 中 #{} 防 SQL 注入(预编译),${} 是拼接(危险!别用) |
| 动态 SQL | <if>, <where>, <foreach> 标签,条件拼接 SQL |
| N+1 问题 | JPA 查列表时,每条数据再查一次关联表 → 查询次数爆炸,用 JOIN FETCH 解决 |
三、缓存 — Redis
作用
把热点数据放内存里,避免每次都查数据库,快!
典型使用场景
场景1:首页热门商品 → 查一次数据库,结果存 Redis,后续直接读缓存
场景2:短信验证码 → 生成后存 Redis,设 5 分钟过期
场景3:分布式 Session → 多台服务器共享登录状态
场景4:排行榜/计数器 → Redis 的 ZSET 天然支持
Spring Boot 中怎么用
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置
spring:
redis:
host: localhost
port: 6379
password: 123456
database: 0
代码使用
@Autowired
private StringRedisTemplate redisTemplate;
// 存值(设置 5 分钟过期)
redisTemplate.opsForValue().set("sms:13800138000", "123456", 5, TimeUnit.MINUTES);
// 取值
String code = redisTemplate.opsForValue().get("sms:13800138000");
关键知识点
| 缓存穿透 | 查一个根本不存在的数据,每次都打到数据库 → 用布隆过滤器或缓存空值 |
| 缓存击穿 | 某个热点 key 过期,大量请求瞬间打到数据库 → 加互斥锁 |
| 缓存雪崩 | 大量 key 同时过期 → 过期时间加随机值 |
| 数据一致性 | 先更新数据库,再删缓存(而不是更新缓存) |
四、消息队列 — RabbitMQ / Kafka
作用
系统之间异步通信,解耦 + 削峰。
通俗理解
没有消息队列:
用户下单 → 扣库存 → 发短信 → 发邮件 → 更新积分 → 返回
(全串行,一个慢了后面的都等着)
有了消息队列:
用户下单 → 扣库存 → 把"发短信、发邮件、更新积分"扔进队列 → 立即返回
(后台慢慢消费,用户不用等)
RabbitMQ vs Kafka
| 擅长 | 可靠消息传递 | 高吞吐日志/流处理 |
| 消息模型 | 队列(一条消息只消费一次) | 发布/订阅(可多人消费) |
| 适合场景 | 订单通知、任务分发 | 日志收集、大数据管道 |
Spring Boot 中怎么用(以 RabbitMQ 为例)
// 1. 发送消息
@Autowired
private RabbitTemplate rabbitTemplate;
public void createOrder(Order order) {
// …保存订单
rabbitTemplate.convertAndSend("order.exchange", "order.create", order);
return "下单成功";
}
// 2. 监听消费
@Component
public class OrderConsumer {
@RabbitListener(queues = "order.queue")
public void handleOrder(Order order) {
smsService.sendSms(order.getPhone());
emailService.sendEmail(order.getEmail());
}
}
关键知识点
| 消息丢失 | 发送端确认 + 持久化 + 消费端手动 ACK |
| 消息重复 | 消费端做幂等处理(比如用唯一 ID 去重) |
| 死信队列 | 消费失败的消息放到专门队列,后续处理 |
五、安全 — Spring Security + JWT
登录流程
1. 用户提交 用户名+密码 → 后端验证
2. 验证通过 → 生成一个 JWT Token 返回给前端
3. 前端把 Token 存起来(localStorage / Cookie)
4. 以后每次请求都带上 Token → 后端验证 Token 是否合法
代码示例
// 登录接口
@PostMapping("/login")
public String login(@RequestBody LoginRequest request) {
// 1. 验证用户名密码
User user = userService.validate(request.getUsername(), request.getPassword());
// 2. 生成 Token
String token = JwtUtil.generateToken(user.getId(), user.getRole());
return token;
}
// 拦截器里验证 Token
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) {
String token = req.getHeader("Authorization");
if (token == null || !JwtUtil.verify(token)) {
resp.setStatus(401);
return false; // 拦截
}
return true; // 放行
}
}
关键知识点
| JWT 三部分 | Header(算法)+ Payload(数据)+ Signature(签名防篡改) |
| Token 过期 | 一般设 2 小时,过期后需重新登录或用 Refresh Token 续期 |
| RBAC | 基于角色的权限控制:管理员/普通用户/游客,不同角色不同权限 |
六、跨域 — CORS
为什么会有跨域问题?
前端:http://localhost:5173 (Vue 开发服务器)
后端:http://localhost:8080 (Spring Boot)
浏览器说:端口不同,不允许!→ 跨域错误
解决方案
// 方式1:单个接口
@CrossOrigin(origins = "http://localhost:5173")
@GetMapping("/api/users")
public List<User> getUsers() { … }
// 方式2:全局配置(推荐)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173")
.allowedMethods("*")
.allowCredentials(true);
}
}
七、项目分层结构(标准写法)
src/main/java/com/example/
├── controller/ ← 接收请求,返回结果(接待员)
│ └── UserController.java
├── service/ ← 业务逻辑(大厨)
│ ├── UserService.java
│ └── impl/
│ └── UserServiceImpl.java
├── mapper/ ← 操作数据库(采购员)
│ └── UserMapper.java
├── entity/ ← 数据库实体(菜单)
│ └── User.java
├── dto/ ← 前端传过来的数据格式
│ └── LoginRequest.java
├── vo/ ← 返回给前端的数据格式
│ └── UserVO.java
├── config/ ← 配置类
│ ├── CorsConfig.java
│ └── SecurityConfig.java
├── common/ ← 通用工具、常量、异常处理
│ └── Result.java
└── Application.java ← 启动类
调用链路
前端请求 → Controller → Service → Mapper → 数据库
↓
Redis缓存(可选)
↓
消息队列(可选)
八、总结
┌─────────────────────────────────────────────────┐
│ 前端 (Vue/React) │
│ http://localhost:5173 │
└─────────────┬───────────────────────────────────┘
│ HTTP 请求 (JSON)
▼
┌─────────────────────────────────────────────────┐
│ Spring Boot (localhost:8080) │
│ │
│ Controller ──→ Service ──→ Mapper ──→ MySQL │
│ │ │
│ ├──→ Redis (缓存) │
│ └──→ RabbitMQ (异步消息) │
│ │
│ Security + JWT (拦截未登录请求) │
│ CORS (解决跨域) │
└─────────────────────────────────────────────────┘




