1. 项目概述
这个前后端分离的在线宠物用品交易系统,是我去年为一个创业团队开发的核心项目。采用SpringBoot+Vue+MyBatis+MySQL的技术栈组合,经过半年多的实际运营验证,系统稳定支持日均3000+订单的处理量。下面我将从架构设计到部署上线的完整过程进行拆解,特别会分享在实际业务场景中遇到的性能优化问题和解决方案。
2. 技术选型解析
2.1 后端技术栈
SpringBoot 2.7.3作为基础框架,主要考虑其:
- 内嵌Tomcat简化部署
- 自动配置减少XML配置
- 与MyBatis的天然集成优势
数据库选用MySQL 8.0而非5.7版本,主要因为:
- JSON字段支持更好(用于存储商品规格参数)
- 窗口函数便于销售数据分析
- 性能提升30%以上(实测QPS)
2.2 前端技术栈
Vue 3.2 + Element Plus的组合,特别适合电商类项目:
- Composition API使代码组织更清晰
- 按需引入减少打包体积(最终chunk减小40%)
- TypeScript支持完善(采用TS严格模式)
3. 核心模块实现
3.1 商品模块设计
商品表采用纵向分表策略:
CREATE TABLE `product` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL COMMENT '商品名称', `category_id` int NOT NULL COMMENT '分类ID', `price` decimal(10,2) NOT NULL COMMENT '售价', `stock` int NOT NULL DEFAULT '0' COMMENT '库存', `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态', PRIMARY KEY (`id`), KEY `idx_category` (`category_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `product_spec` ( `product_id` bigint NOT NULL, `spec_json` json NOT NULL COMMENT '规格参数', PRIMARY KEY (`product_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3.2 购物车实现
采用Redis Hash结构存储购物车数据:
// 购物车数据结构示例 { "userId:1001": { "product:202": { "quantity": 2, "selected": true, "addTime": 1634567890 } } }重要提示:必须设置Redis过期时间(建议7天),避免无效数据堆积
4. 性能优化实践
4.1 缓存策略
采用多级缓存方案:
- 本地Caffeine缓存(高频访问数据)
- Redis集群缓存(全量数据)
- MySQL持久层
缓存更新采用Write-Through模式:
@CachePut(value = "products", key = "#product.id") public Product updateProduct(Product product) { productMapper.updateById(product); return product; }4.2 数据库优化
针对商品列表查询的慢SQL问题,我们:
- 添加复合索引:
(category_id, status, price) - 使用覆盖索引避免回表
- 大分页改用游标方式
优化前后对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| QPS | 120 | 850 |
| 平均响应时间 | 450ms | 65ms |
5. 部署方案
5.1 服务器配置
推荐生产环境配置:
- 前端:Nginx(2C4G)
- 后端:SpringBoot(4C8G)×2
- 数据库:MySQL(8C16G)+ Redis(4C8G)
5.2 容器化部署
使用Docker Compose编排:
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - ./mysql/data:/var/lib/mysql ports: - "3306:3306" redis: image: redis:6 command: redis-server --requirepass ${REDIS_PASSWORD} ports: - "6379:6379"6. 踩坑记录
Vue路由问题:
- 现象:刷新页面后路由丢失
- 原因:history模式需要Nginx配置
- 解决:添加try_files规则
location / { try_files $uri $uri/ /index.html; }MyBatis批量插入:
- 错误做法:循环执行单条insert
- 正确方案:使用
<foreach>标签
<insert id="batchInsert"> INSERT INTO order_detail (order_id, product_id, quantity) VALUES <foreach collection="list" item="item" separator=","> (#{item.orderId}, #{item.productId}, #{item.quantity}) </foreach> </insert>
这个项目让我深刻体会到,电商系统的核心在于处理好"三高"问题:高并发、高可用、高性能。特别是在促销活动时,提前做好压力测试和熔断方案至关重要。建议开发阶段就引入JMeter进行基准测试,我们通过这种方式提前发现了多个性能瓶颈。