1. 项目概述:SpringBoot服装商城销售系统
这个基于SpringBoot框架的服装商城销售系统,本质上是一个典型的B2C电商平台。我在实际开发中发现,服装类电商与其他垂直领域最大的区别在于SKU管理复杂(颜色、尺码等多维度属性)、季节性强(需要快速调整商品展示策略)、视觉要求高(详情页需要支持多图展示)。系统采用SpringBoot 2.7.x版本开发,实测在4核8G服务器上可稳定支撑5000+的并发访问量。
2. 核心模块设计思路
2.1 分层架构设计
采用经典的四层架构:
- 表现层:Thymeleaf模板引擎 + Bootstrap5响应式布局
- 业务层:Spring MVC + 自定义注解实现权限控制
- 持久层:MyBatis-Plus 3.5.3 + 动态数据源(主从分离)
- 存储层:MySQL 8.0 + Redis 7.0缓存
特别提醒:商品服务与订单服务需要物理分离部署,避免大促时库存扣减影响核心交易链路
2.2 数据库关键表结构
sql复制# 商品核心表(简化版)
CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'SPU ID',
`category_id` int NOT NULL COMMENT '类目ID',
`title` varchar(120) NOT NULL COMMENT '商品标题',
`sub_title` varchar(200) DEFAULT NULL COMMENT '副标题',
`main_image` varchar(255) DEFAULT NULL COMMENT '主图URL',
`price` decimal(10,2) NOT NULL COMMENT '基准价',
`status` tinyint DEFAULT '1' COMMENT '状态',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# SKU表(关键设计)
CREATE TABLE `product_sku` (
`id` bigint NOT NULL AUTO_INCREMENT,
`product_id` bigint NOT NULL,
`attributes` json DEFAULT NULL COMMENT '{"color":"red","size":"XL"}',
`price` decimal(10,2) NOT NULL,
`stock` int NOT NULL DEFAULT '0',
`image` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_product` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心技术实现细节
3.1 商品详情页性能优化
采用多级缓存策略:
- Redis缓存商品基础信息(设置30分钟过期)
- Caffeine本地缓存SKU列表(最大1000条,5分钟过期)
- 静态化详情页HTML(商品变更时触发重新生成)
java复制// 缓存配置示例
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
return RedisCacheManager.builder(factory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.disableCachingNullValues())
.build();
}
@Bean
public CaffeineCacheManager caffeineCacheManager() {
Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES);
return new CaffeineCacheManager("skuCache", caffeine);
}
}
3.2 高并发库存扣减方案
实现分布式锁+乐观锁双重保障:
- Redis分布式锁防止超卖
- 数据库乐观锁确保最终一致性
java复制@Transactional
public boolean reduceStock(Long skuId, Integer quantity) {
String lockKey = "stock_lock:" + skuId;
try {
// 获取分布式锁(3秒超时)
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("系统繁忙,请重试");
}
// 乐观锁更新
int affected = productSkuMapper.updateStock(skuId, quantity);
return affected > 0;
} finally {
redisTemplate.delete(lockKey);
}
}
// MyBatis更新语句
<update id="updateStock">
UPDATE product_sku
SET stock = stock - #{quantity}
WHERE id = #{skuId} AND stock >= #{quantity}
</update>
4. 典型问题排查实录
4.1 支付回调重复处理
现象:用户支付成功后,订单状态被多次更新
解决方案:
- 在支付日志表添加唯一索引(order_id + transaction_id)
- 回调处理增加幂等判断
java复制@Transactional
public void handlePayNotify(PayNotifyDTO dto) {
// 检查是否已处理过
if (payLogMapper.existsByOrderAndTransaction(
dto.getOrderId(), dto.getTransactionId())) {
return;
}
// 处理业务逻辑
orderService.updateStatus(dto.getOrderId(), PAID);
// 记录日志
payLogMapper.insert(new PayLog(dto));
}
4.2 商品搜索性能瓶颈
现象:关键词搜索响应时间超过2秒
优化步骤:
- 为商品表添加全文索引
- 引入Elasticsearch实现二级搜索
- 搜索结果缓存5分钟
java复制// 混合查询策略
public Page<ProductVO> search(String keyword, Integer page, Integer size) {
// 先查缓存
String cacheKey = "search:" + keyword + ":" + page;
String cached = redisTemplate.opsForValue().get(cacheKey);
if (cached != null) {
return JSON.parseObject(cached, new TypeReference<>() {});
}
// 无缓存则查询ES
SearchResponse response = elasticsearchTemplate.search(
new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "sub_title"))
.withPageable(PageRequest.of(page, size))
.build(),
ProductDocument.class);
// 处理结果并缓存
Page<ProductVO> result = convertToVO(response);
redisTemplate.opsForValue().set(
cacheKey,
JSON.toJSONString(result),
5, TimeUnit.MINUTES);
return result;
}
5. 部署与监控方案
5.1 容器化部署
Docker Compose编排关键服务:
yaml复制version: '3'
services:
app:
image: mall-service:1.0
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
redis:
image: redis:7.0-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=123456
volumes:
- mysql_data:/var/lib/mysql
volumes:
redis_data:
mysql_data:
5.2 监控配置
Spring Boot Actuator + Prometheus + Grafana方案:
- 应用配置:
properties复制management.endpoints.web.exposure.include=*
management.metrics.export.prometheus.enabled=true
- Prometheus抓取配置:
yaml复制scrape_configs:
- job_name: 'mall-service'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']
- Grafana仪表盘关键指标:
- 请求QPS/耗时(99线)
- JVM内存/GC情况
- 数据库连接池使用率
- Redis命中率
6. 扩展功能建议
6.1 推荐系统集成
基于用户行为的协同过滤实现:
- 收集用户浏览/购买记录
- 使用Mahout或Spark MLlib计算相似度
- 实时推荐接口开发
java复制public List<ProductVO> recommendProducts(Long userId) {
// 获取用户特征向量
double[] userVector = userBehaviorService.getUserVector(userId);
// 从Redis获取候选商品
Set<String> candidates = redisTemplate.opsForZSet()
.reverseRange("hot_products", 0, 99);
// 计算相似度并排序
return candidates.stream()
.map(productService::getById)
.sorted(Comparator.comparingDouble(p ->
cosineSimilarity(userVector, p.getFeatureVector())))
.limit(10)
.collect(Collectors.toList());
}
6.2 秒杀功能实现
关键设计方案:
- 独立秒杀服务隔离流量
- Redis预减库存 + 异步下单
- 令牌桶限流(1000QPS)
java复制@RestController
@RequestMapping("/flash")
public class FlashSaleController {
@RateLimiter(value = 1000, timeout = 100)
@PostMapping("/order")
public Result createOrder(@RequestBody OrderDTO dto) {
// 验证令牌
if (!redisTemplate.opsForValue()
.setIfAbsent("token:" + dto.getToken(), "1", 5, TimeUnit.MINUTES)) {
return Result.fail("无效的秒杀令牌");
}
// 发送MQ消息
rocketMQTemplate.asyncSend(
"flash_order_topic",
MessageBuilder.withPayload(dto).build(),
new SendCallback() {
@Override
public void onSuccess(SendResult result) {
log.info("秒杀订单已提交");
}
@Override
public void onException(Throwable e) {
log.error("消息发送失败", e);
}
});
return Result.success("排队处理中");
}
}
