阿飞的博客

← 全部项目

阿飞商城 · afei-mall

查看源码
project.name
技术栈
框架 Spring Boot 3.5 / Spring Cloud Alibaba
持久层 MyBatis-Plus 3.5.15 / MySQL 8
缓存 Redis / Redisson
消息 RabbitMQ(延迟队列)
分布式 Nacos / Seata AT / Gateway
鉴权 JWT 自定义注解
文件 Aliyun OSS
技术亮点
◆ 防超卖:Redisson 锁 + 原子 SQL 两层
◆ 订单超时关闭:延迟消息 + 定时任务 + 补偿重试
◆ 下单链路:Seata 事务、幂等防重、订单快照
◆ JWT 载荷带 jti:踩过一个把自己锁在门外的坑
◆ 订单快照:把商品信息冻结在下单那一刻

这是什么

一个从 0 搭建的 Spring Cloud Alibaba 微服务电商后端。7 个业务服务各自独立部署、各自持有数据库,
跨服务只走 HTTP 调用,不允许直接读别人的库——这是我把「服务边界」真正落地过的第一个项目。

架构

Gateway 统一入口 → Nacos 注册与配置中心 → 各业务服务。
服务之间用 RestTemplate 互调(刻意没用 Feign:我想先把「一次远程调用到底发生了什么」搞明白)。

服务端口职责
mall-auth8010注册 / 登录 / JWT 签发
mall-user8020用户资料、收货地址、头像
mall-product8030分类 / 品牌 / SPU / SKU
mall-cart—购物车(只操作 Redis,不碰 MySQL)
mall-order8040订单创建、快照、超时关闭
mall-payment8050支付编排

四个真正花时间的地方

1. 防超卖:分布式锁 + 原子 SQL

一万人抢一百件库存,光靠 synchronized 显然不够。方案分两层:
Redisson 分布式锁把同一商品的并发请求串行化,原子 SQL(UPDATE ... SET stock = stock - 1 WHERE stock >= 1)
作为最后一道防线。两层缺一不可——锁会因故失效,SQL 不会。

2. 订单超时关闭:延迟队列 + 定时任务双保险

只靠延迟队列,消息可能丢;只靠定时任务,精度又不够。
所以两条路一起走:下单时发一条 30 分钟的延迟消息做正常取消,
同时定时任务每分钟扫一遍超时订单兜底。两者都用幂等的状态判断收口,不会重复取消。

3. 订单快照

订单表不 JOIN 商品表取价,而是把下单那一刻的商品名、价格、缩略图冗余进订单项。
商品后来改名涨价都不影响历史订单——这是我在这个项目里最满意的一个决定。

4. 跨服务一致性:Seata AT 模式

下单要同时写订单库和库存库。两个方案对比过:最终选了 Seata AT(基于 undo_log 回滚),
因为业务侵入小、可读性好,代价是每个参与方都要能开事务。

踩过的坑

项目截图
截图截图截图截图截图