引言
对于中级 Java 开发者而言,搭建一套高可用、高性能的电商后端系统是提升技术实操能力的核心场景。本文将以项目驱动 的方式,从环境搭建到核心功能落地,完整演示基于 Spring Boot 4、Redis、MySQL 构建电商后端的全过程,所有代码均可直接复现,聚焦实战落地,避开纯理论堆砌。


- 引言
- 目录
-
- 一、项目背景与架构概览
-
- [1. 电商后端核心模块](#1. 电商后端核心模块)
- [2. 技术栈选型原因](#2. 技术栈选型原因)
- 二、系统架构流程图
- 三、关键技术实现
-
- 前置准备
- [1. 配置文件(application.yml):Redis 与 MySQL 配置](#1. 配置文件(application.yml):Redis 与 MySQL 配置)
- [2. 数据库表设计:商品表与订单表](#2. 数据库表设计:商品表与订单表)
-
- [(1)商品实体(Product)→ 商品表(product)](#(1)商品实体(Product)→ 商品表(product))
- [(2)订单实体(Order)→ 订单表(t_order,避免与 MySQL 关键字冲突)](#(2)订单实体(Order)→ 订单表(t_order,避免与 MySQL 关键字冲突))
- [3. Spring Data JPA 数据访问层](#3. Spring Data JPA 数据访问层)
-
- [(1)商品 Repository(ProductRepository)](#(1)商品 Repository(ProductRepository))
- [(2)订单 Repository(OrderRepository)](#(2)订单 Repository(OrderRepository))
- [4. 商品查询接口:集成 Redis 缓存(防穿透/雪崩)](#4. 商品查询接口:集成 Redis 缓存(防穿透/雪崩))
-
- (1)商品服务(ProductService):带缓存注解的业务方法
- [(2)商品控制层(ProductController):RESTful 接口](#(2)商品控制层(ProductController):RESTful 接口)
- (3)缓存防护思路说明
- [5. 订单下单接口:Redis 分布式锁防止超卖](#5. 订单下单接口:Redis 分布式锁防止超卖)
-
- [(1)Redis 分布式锁工具类(RedisDistributedLockUtil)](#(1)Redis 分布式锁工具类(RedisDistributedLockUtil))
- (2)订单服务(OrderService):下单业务逻辑(含分布式锁)
- [(3)订单控制层(OrderController):RESTful 下单接口](#(3)订单控制层(OrderController):RESTful 下单接口)
- 四、部署与验证建议
-
- [1. 本地启动服务步骤](#1. 本地启动服务步骤)
- [2. 接口验证(curl 或 Postman)](#2. 接口验证(curl 或 Postman))
-
- [(1)商品查询接口验证(curl 命令)](#(1)商品查询接口验证(curl 命令))
- [(2)订单下单接口验证(curl 命令)](#(2)订单下单接口验证(curl 命令))
- [3. 性能优化方向](#3. 性能优化方向)
- 五、总结
目录
一、项目背景与架构概览
1. 电商后端核心模块
典型电商后端的核心业务模块围绕用户购物流程展开,核心包括:
- 用户模块:负责用户注册、登录、信息维护(本文聚焦核心流程,暂不深入实现);
- 商品模块:商品信息查询、库存维护,是电商系统的基础,也是高并发场景的核心入口;
- 购物车模块:临时存储用户待购商品,依赖缓存提升访问性能;
- 订单模块:处理下单、订单状态流转,存在超卖等并发问题,是系统高可用的关键验证点。
本文将以**商品模块(查询+库存)和订单模块(下单防超卖)**为核心,落地全套技术栈。
2. 技术栈选型原因
为何选择 Spring Boot 4 + Redis + MySQL 这套组合?
- Spring Boot 4:基于 Spring 6.1 构建,兼容 Java 17+,提供了更轻量化的自动配置、更快的启动速度和更好的原生虚拟线程支持,大幅降低分布式应用的开发门槛,是当前 Java 后端微服务开发的首选框架;
- Redis :高性能的内存数据库,支持多种数据结构,既可以作为热点数据缓存 提升查询接口吞吐量,也可以实现分布式锁解决分布式环境下的并发问题(如超卖),同时支持持久化,兼顾性能与数据安全性;
- MySQL:成熟稳定的关系型数据库,支持事务和复杂查询,适合存储商品、订单等需要持久化、强一致性的核心业务数据,是电商系统持久化存储的标配。
三者组合实现了「高性能缓存 + 强一致性持久化 + 高效开发框架」的黄金搭配,能够满足电商系统高并发、高可用的核心需求。
二、系统架构流程图
以下使用 Mermaid 绘制系统架构图,清晰展示客户端、Spring Boot 应用、Redis、MySQL 之间的数据流向和交互关系:
存在
不存在
获取失败
获取成功
库存不足
库存充足
客户端(App/前端)
Spring Boot 4 应用
商品查询接口
订单下单接口
Redis 缓存是否存在?
从 Redis 读取商品数据
从 MySQL 读取商品数据
将商品数据写入 Redis 缓存(防穿透/雪崩)
通过 Redis 分布式锁获取下单权限
返回下单失败/请重试
校验 MySQL 商品库存
释放 Redis 分布式锁
扣减 MySQL 商品库存
创建 MySQL 订单记录
释放 Redis 分布式锁
返回下单成功
MySQL 数据库(商品表/订单表)
Redis 缓存(热点商品/分布式锁)
三、关键技术实现
前置准备
- 环境要求:Java 17+、Maven 3.8+、Redis 6.0+、MySQL 8.0+;
- 项目依赖(pom.xml 核心依赖,Spring Boot 4 版本以 4.0.0 为例):
xml
<!-- Spring Boot 父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0</version>
<relativePath/>
</parent>
<dependencies>
<!-- Web 启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data JPA 启动器(操作 MySQL) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Redis 启动器(缓存+分布式锁) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok(简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
1. 配置文件(application.yml):Redis 与 MySQL 配置
在 src/main/resources 下创建 application.yml,完成 Redis 和 MySQL 的配置,同时开启 Spring 缓存注解支持:
yaml
# 服务器配置
server:
port: 8080
tomcat:
threads:
max: 200 # 调整 Tomcat 最大线程数,提升并发能力
# Spring 配置
spring:
# 数据源(MySQL)配置
datasource:
url: jdbc:mysql://localhost:3306/ecommerce_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
username: root # 你的 MySQL 用户名
password: root # 你的 MySQL 密码
driver-class-name: com.mysql.cj.jdbc.Driver
# 连接池配置(性能优化)
hikari:
maximum-pool-size: 20 # 最大连接数
minimum-idle: 5 # 最小空闲连接数
connection-timeout: 30000 # 连接超时时间(ms)
# JPA 配置
jpa:
hibernate:
ddl-auto: update # 自动创建/更新数据表(生产环境建议改为 none)
show-sql: true # 打印 SQL 语句
properties:
hibernate:
format_sql: true # 格式化 SQL 语句
dialect: org.hibernate.dialect.MySQL8Dialect # MySQL 8 方言
# Redis 配置
data:
redis:
host: localhost # Redis 主机地址
port: 6379 # Redis 端口
password: "" # Redis 密码(无密码则留空)
database: 0 # 操作的 Redis 数据库索引
timeout: 3000 # 连接超时时间(ms)
# Redis 连接池配置
lettuce:
pool:
max-active: 16 # 最大连接数
max-idle: 8 # 最大空闲连接数
min-idle: 4 # 最小空闲连接数
# 缓存配置(自定义 Redis 缓存过期时间,防缓存雪崩)
spring:
cache:
redis:
time-to-live: 3600000 # 缓存默认过期时间 1 小时(ms)
cache-null-values: true # 缓存 null 值,防缓存穿透
# 日志配置
logging:
level:
org.springframework.web: INFO
com.ecommerce: DEBUG # 自定义项目包日志级别
2. 数据库表设计:商品表与订单表
基于 JPA 注解自动生成数据表,核心实体类如下(对应 MySQL 表结构):
(1)商品实体(Product)→ 商品表(product)
java
package com.ecommerce.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 商品实体类,对应 MySQL product 表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "product")
public class Product {
/**
* 商品主键 ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 商品名称
*/
@Column(name = "product_name", nullable = false, length = 100)
private String productName;
/**
* 商品价格
*/
@Column(name = "price", nullable = false, precision = 10, scale = 2)
private BigDecimal price;
/**
* 商品库存
*/
@Column(name = "stock", nullable = false)
private Integer stock;
/**
* 商品描述
*/
@Column(name = "description", length = 500)
private String description;
}
(2)订单实体(Order)→ 订单表(t_order,避免与 MySQL 关键字冲突)
java
package com.ecommerce.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
/**
* 订单实体类,对应 MySQL t_order 表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "t_order")
public class Order {
/**
* 订单主键 ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 订单编号(唯一)
*/
@Column(name = "order_no", nullable = false, unique = true, length = 32)
private String orderNo;
/**
* 商品 ID
*/
@Column(name = "product_id", nullable = false)
private Long productId;
/**
* 购买数量
*/
@Column(name = "buy_count", nullable = false)
private Integer buyCount;
/**
* 订单总金额
*/
@Column(name = "total_amount", nullable = false, precision = 10, scale = 2)
private BigDecimal totalAmount;
/**
* 创建时间
*/
@Column(name = "create_time", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
}
3. Spring Data JPA 数据访问层
创建 Repository 接口,继承 JpaRepository,无需手动实现 CRUD 方法:
(1)商品 Repository(ProductRepository)
java
package com.ecommerce.repository;
import com.ecommerce.entity.Product;
import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* 商品数据访问层
*/
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
/**
* 查询商品并加悲观锁(防止库存并发修改)
* @param productId 商品 ID
* @return 商品信息
*/
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE p.id = :productId")
Optional<Product> findByIdWithPessimisticLock(Long productId);
}
(2)订单 Repository(OrderRepository)
java
package com.ecommerce.repository;
import com.ecommerce.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* 订单数据访问层
*/
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
}
4. 商品查询接口:集成 Redis 缓存(防穿透/雪崩)
使用 Spring 缓存注解 @Cacheable 快速实现 Redis 缓存,同时加入缓存穿透、雪崩的防护策略。
(1)商品服务(ProductService):带缓存注解的业务方法
java
package com.ecommerce.service;
import com.ecommerce.entity.Product;
import com.ecommerce.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.Optional;
/**
* 商品服务层
*/
@Service
@RequiredArgsConstructor
public class ProductService {
private final ProductRepository productRepository;
/**
* 根据商品 ID 查询商品信息(集成 Redis 缓存)
* @param productId 商品 ID
* @return 商品信息
*/
@Cacheable(value = "productCache", key = "#productId", unless = "#result == null")
// 注解说明:
// value:缓存名称(对应 Redis 中的 key 前缀)
// key:缓存键(使用商品 ID 作为唯一标识)
// unless:结果为 null 时不缓存(配合 application.yml 中 cache-null-values: true,实现空值缓存防穿透)
public Product getProductById(Long productId) {
// 缓存不存在时,从 MySQL 查询
Optional<Product> productOptional = productRepository.findById(productId);
// 若商品不存在,返回 null(会被 Redis 缓存空值,防止缓存穿透)
return productOptional.orElse(null);
}
}
(2)商品控制层(ProductController):RESTful 接口
java
package com.ecommerce.controller;
import com.ecommerce.entity.Product;
import com.ecommerce.service.ProductService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 商品 RESTful 接口控制层
*/
@RestController
@RequestMapping("/api/products")
@RequiredArgsConstructor
public class ProductController {
private final ProductService productService;
/**
* 根据商品 ID 查询商品信息
* @param productId 商品 ID
* @return 商品信息响应
*/
@GetMapping("/{productId}")
public ResponseEntity<Product> getProductById(@PathVariable Long productId) {
Product product = productService.getProductById(productId);
if (product != null) {
return ResponseEntity.ok(product);
} else {
return ResponseEntity.notFound().build();
}
}
}
(3)缓存防护思路说明
- 缓存穿透 :通过
spring.cache.redis.cache-null-values: true缓存 null 值,避免恶意请求(查询不存在的商品 ID)直接穿透到 MySQL,同时给空值缓存设置较短过期时间(可自定义扩展); - 缓存雪崩 :通过
spring.cache.redis.time-to-live: 3600000设置缓存默认过期时间,同时可在@Cacheable注解中为不同商品设置随机过期时间(避免大量缓存同时失效),另外依赖 Redis 集群提高缓存服务可用性; - 缓存击穿:针对热点商品(如秒杀商品),可采用「互斥锁」或「永不过期+主动更新」策略,本文后续分布式锁可复用解决该问题。
5. 订单下单接口:Redis 分布式锁防止超卖
超卖问题是电商下单场景的典型并发问题,分布式环境下单台服务器的本地锁(synchronized、Lock)无法生效,需通过 Redis 分布式锁实现跨服务的并发控制。
(1)Redis 分布式锁工具类(RedisDistributedLockUtil)
基于 RedisTemplate 实现,利用 Redis 的 setnx 命令(原子操作)实现锁的获取,同时加入过期时间防止死锁:
java
package com.ecommerce.util;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* Redis 分布式锁工具类
*/
@Component
@RequiredArgsConstructor
public class RedisDistributedLockUtil {
private final RedisTemplate<String, Object> redisTemplate;
// 锁的前缀(区分不同业务的锁)
private static final String LOCK_PREFIX = "ecommerce:lock:";
// 锁的默认过期时间(30s,防止死锁)
private static final long DEFAULT_LOCK_EXPIRE_TIME = 30;
// 锁的默认获取超时时间(5s)
private static final long DEFAULT_ACQUIRE_TIMEOUT = 5;
/**
* 获取分布式锁
* @param lockKey 锁的业务标识(如商品 ID)
* @return 锁的唯一标识(用于释放锁),获取失败返回 null
*/
public String acquireLock(String lockKey) {
return acquireLock(lockKey, DEFAULT_ACQUIRE_TIMEOUT, DEFAULT_LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
}
/**
* 带参数获取分布式锁
* @param lockKey 锁的业务标识
* @param acquireTimeout 获取锁的超时时间
* @param lockExpireTime 锁的过期时间
* @param timeUnit 时间单位
* @return 锁的唯一标识,获取失败返回 null
*/
public String acquireLock(String lockKey, long acquireTimeout, long lockExpireTime, TimeUnit timeUnit) {
// 生成唯一标识(防止误删其他线程的锁)
String lockValue = UUID.randomUUID().toString();
String realLockKey = LOCK_PREFIX + lockKey;
long acquireEndTime = System.currentTimeMillis() + timeUnit.toMillis(acquireTimeout);
// 循环尝试获取锁,直到超时
while (System.currentTimeMillis() < acquireEndTime) {
// Redis set 命令:NX(不存在才设置)、PX(过期时间单位 ms)
Boolean success = redisTemplate.opsForValue().setIfAbsent(
realLockKey,
lockValue,
lockExpireTime,
TimeUnit.SECONDS
);
// 成功获取锁
if (Boolean.TRUE.equals(success)) {
return lockValue;
}
// 获取失败,短暂休眠后重试
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
// 超时未获取到锁
return null;
}
/**
* 释放分布式锁(使用 Lua 脚本保证原子操作)
* @param lockKey 锁的业务标识
* @param lockValue 锁的唯一标识
* @return 是否释放成功
*/
public boolean releaseLock(String lockKey, String lockValue) {
if (lockValue == null) {
return false;
}
String realLockKey = LOCK_PREFIX + lockKey;
// Lua 脚本:判断锁的 value 是否与传入的一致,一致则删除(避免误删)
String luaScript = """
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
""";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(luaScript);
redisScript.setResultType(Long.class);
// 执行 Lua 脚本
Long result = redisTemplate.execute(
redisScript,
Collections.singletonList(realLockKey),
lockValue
);
// 返回释放结果(1 表示成功,0 表示失败)
return result != null && result > 0;
}
}
(2)订单服务(OrderService):下单业务逻辑(含分布式锁)
java
package com.ecommerce.service;
import com.ecommerce.entity.Order;
import com.ecommerce.entity.Product;
import com.ecommerce.repository.OrderRepository;
import com.ecommerce.repository.ProductRepository;
import com.ecommerce.util.RedisDistributedLockUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;
/**
* 订单服务层
*/
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
private final ProductRepository productRepository;
private final RedisDistributedLockUtil redisDistributedLockUtil;
/**
* 下单接口(防止超卖)
* @param productId 商品 ID
* @param buyCount 购买数量
* @return 下单结果
*/
@Transactional(rollbackFor = Exception.class) // 事务注解,保证库存扣减和订单创建的原子性
public String createOrder(Long productId, Integer buyCount) {
// 1. 参数校验
if (productId == null || buyCount == null || buyCount <= 0) {
return "参数错误,请输入有效的商品 ID 和购买数量";
}
// 2. 构建分布式锁的 key(以商品 ID 为标识,同一商品同一时间只允许一个线程下单)
String lockKey = "product:order:" + productId;
String lockValue = null;
try {
// 3. 获取分布式锁
lockValue = redisDistributedLockUtil.acquireLock(lockKey);
if (lockValue == null) {
return "下单过于火爆,请稍后再试";
}
// 4. 查询商品(加悲观锁,防止库存并发修改)
Product product = productRepository.findByIdWithPessimisticLock(productId)
.orElseThrow(() -> new RuntimeException("商品不存在"));
// 5. 校验库存
if (product.getStock() < buyCount) {
return "商品库存不足,当前库存:" + product.getStock();
}
// 6. 扣减商品库存
product.setStock(product.getStock() - buyCount);
productRepository.save(product);
// 7. 创建订单
Order order = new Order();
order.setOrderNo(UUID.randomUUID().toString().replace("-", ""));
order.setProductId(productId);
order.setBuyCount(buyCount);
order.setTotalAmount(product.getPrice().multiply(new BigDecimal(buyCount)));
order.setCreateTime(new Date());
orderRepository.save(order);
// 8. 返回下单成功结果
return "下单成功,订单编号:" + order.getOrderNo();
} catch (Exception e) {
return "下单失败:" + e.getMessage();
} finally {
// 9. 释放分布式锁(无论下单成功与否,都要释放锁)
if (lockValue != null) {
redisDistributedLockUtil.releaseLock(lockKey, lockValue);
}
}
}
}
(3)订单控制层(OrderController):RESTful 下单接口
java
package com.ecommerce.controller;
import com.ecommerce.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 订单 RESTful 接口控制层
*/
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
/**
* 创建订单(下单接口)
* @param productId 商品 ID
* @param buyCount 购买数量
* @return 下单结果响应
*/
@PostMapping("/create")
public ResponseEntity<String> createOrder(
@RequestParam Long productId,
@RequestParam Integer buyCount
) {
String result = orderService.createOrder(productId, buyCount);
return ResponseEntity.ok(result);
}
}
四、部署与验证建议
1. 本地启动服务步骤
- 启动 Redis:确保 Redis 服务正常运行(可通过
redis-cli ping验证,返回 PONG 即为正常); - 启动 MySQL:创建数据库
ecommerce_db(与 application.yml 中配置一致),无需手动创建数据表,JPA 会自动生成; - 启动 Spring Boot 应用:运行项目的主启动类(添加
@SpringBootApplication和@EnableCaching注解):
java
package com.ecommerce;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
/**
* 项目主启动类
*/
@SpringBootApplication
@EnableCaching // 开启 Spring 缓存注解支持
public class EcommerceApplication {
public static void main(String[] args) {
SpringApplication.run(EcommerceApplication.class, args);
}
}
- 验证服务启动:访问
http://localhost:8080/api/products/1(若未添加商品,返回 404;可先通过 MySQL 手动插入商品数据)。
2. 接口验证(curl 或 Postman)
(1)商品查询接口验证(curl 命令)
bash
# 查询商品 ID 为 1 的商品信息
curl -X GET http://localhost:8080/api/products/1
- 第一次请求:Redis 缓存无数据,从 MySQL 读取并写入 Redis,控制台打印 SQL 语句;
- 第二次请求:Redis 缓存有数据,直接从 Redis 读取,控制台不打印 SQL 语句,响应速度更快。
(2)订单下单接口验证(curl 命令)
bash
# 购买商品 ID 为 1 的商品,购买数量为 2
curl -X POST "http://localhost:8080/api/orders/create?productId=1&buyCount=2"
- 正常情况:返回「下单成功,订单编号:xxx」,MySQL 中商品库存扣减 2,同时创建订单记录;
- 库存不足:返回「商品库存不足,当前库存:xxx」;
- 并发下单:可通过 JMeter 模拟多线程并发请求,验证无超卖问题(库存不会出现负数)。
3. 性能优化方向
- 连接池优化 :
- MySQL 连接池(HikariCP):根据服务器配置调整
maximum-pool-size(建议不超过 CPU 核心数 * 2 + 1),避免连接过多导致数据库压力过大; - Redis 连接池(Lettuce):调整
max-active、max-idle参数,避免频繁创建/销毁连接,提升 Redis 操作效率。
- MySQL 连接池(HikariCP):根据服务器配置调整
- 缓存策略调优 :
- 分层缓存:热点商品采用「本地缓存(Caffeine)+ Redis 缓存」双层缓存,进一步降低 Redis 压力;
- 缓存预热:系统启动时主动将热点商品数据写入 Redis 缓存,避免高峰期缓存穿透;
- 过期时间优化:不同商品设置不同过期时间(如秒杀商品过期时间较短,普通商品过期时间较长),避免缓存雪崩。
- 分布式锁优化 :
- 采用 Redisson 替代手动实现的 Redis 分布式锁,Redisson 支持锁的自动续期(解决长业务执行时锁过期问题)、公平锁等高级特性;
- 锁粒度细化:将商品级别的锁细化为库存区域级别的锁,提升并发下单能力。
- 数据库优化 :
- 索引优化:为商品表的
id、订单表的product_id、order_no建立索引,提升查询效率; - 分库分表:针对海量订单数据,采用分库分表(如 Sharding-JDBC),提升数据库存储和查询能力;
- 读写分离:采用 MySQL 主从复制,读操作走从库,写操作走主库,缓解主库压力。
- 索引优化:为商品表的
五、总结
本文以项目驱动的方式,完整实现了基于 Spring Boot 4 + Redis + MySQL 的电商后端核心功能,涵盖了环境搭建、配置文件编写、数据库设计、缓存集成、分布式锁防超卖等关键技术点。通过这套方案,能够满足电商系统高并发、高可用的核心需求,同时所有代码均可直接复现,便于中级 Java 开发者落地实践。
后续可在此基础上扩展用户模块、支付模块、物流模块等,逐步构建完整的电商后端系统,同时深入研究微服务、消息队列(如 RocketMQ、RabbitMQ)等技术,进一步提升系统的可扩展性和容错能力。
✨ 坚持用 清晰易懂的图解 + 代码语言, 让每个知识点都 简单直观 !
🚀 个人主页 :不呆头 · CSDN
🌱 代码仓库 :不呆头 · Gitee
📌 专栏系列 :
💬 座右铭 : "不患无位,患所以立。"
