引言:每一个Java商城系统,都是从一台服务器开始的
2015年,我第一次参与开发一个电商系统。当时的技术栈很简单:一台Tomcat服务器、一个MySQL数据库、一套SSH(Struts+Spring+Hibernate)框架。日均订单量不过几百单,系统跑得还算顺畅。
到了2018年,日均订单量突破了5万单。那台Tomcat已经不堪重负,频繁出现OOM(内存溢出)。数据库的慢查询日志长得让人绝望。我们不得不开始重构。
这个故事,几乎是每一个Java商城系统的成长缩影。本文将以一个真实项目的演进历程为主线,分享Java商城系统的技术选型思路和实战经验。
一、第一阶段:单体架构——快速上线验证
技术选型
|
层面 |
技术组件 |
选型理由 |
|---|---|---|
|
框架 |
Spring Boot + MyBatis |
开发效率高,社区活跃 |
|
数据库 |
MySQL 5.7 |
成熟稳定,满足初期需求 |
|
缓存 |
Redis |
热点数据缓存,Session共享 |
|
前端 |
Thymeleaf + jQuery |
服务端渲染,SEO友好 |
适用场景
创业初期,团队人数少于10人
日均订单量低于1万单
业务逻辑相对简单,不需要复杂的分布式事务
踩过的坑
数据库连接池耗尽:初期没有合理配置连接池大小,高峰期出现数据库连接等待超时。解决方案:配置HikariCP连接池,设置最大连接数为CPU核心数的2倍。
慢查询拖垮数据库:商品列表页的SQL没有加索引,每次查询都要全表扫描。解决方案:使用慢查询日志定位问题SQL,添加复合索引。
Session丢失:多台服务器部署后,用户登录状态丢失。解决方案:引入Redis集中管理Session。

二、第二阶段:SOA架构——服务化改造
为什么要拆分?
当系统发展到一定程度,单体架构的问题开始暴露:
耦合严重:修改订单模块的代码,可能导致支付模块出问题
部署困难:一个小小的改动,需要重新部署整个应用
扩展不均:订单模块需要更多资源,但无法单独扩容
拆分策略
按照业务边界,将系统拆分为多个独立的服务:
纯文本纯文本┌─────────────────────────────────────┐ │ API Gateway │ ├──────────┬──────────┬───────────────┤ │ 商品服务 │ 订单服务 │ 支付服务 │ ├──────────┼──────────┼───────────────┤ │ 用户服务 │ 库存服务 │ 营销服务 │ ├──────────┴──────────┴───────────────┤ │ 公共服务层 │ │ (Dubbo/Zookeeper 服务治理) │ └─────────────────────────────────────┘
技术选型
RPC框架:Dubbo(阿里开源,性能优异,适合内部服务调用)
注册中心:Zookeeper/Nacos
分布式事务:TCC模式(Try-Confirm-Cancel),适用于跨服务的资金操作
踩过的坑
分布式事务一致性问题:订单创建涉及商品服务(扣库存)、订单服务(生成订单)、支付服务(冻结资金)。任何一个步骤失败,都需要回滚所有操作。解决方案:引入TCC事务框架,配合补偿机制,确保最终一致性。
服务间调用超时:某个服务响应变慢,导致调用方线程阻塞,最终引发连锁故障。解决方案:设置合理的超时时间和熔断阈值,引入Hystrix熔断器。
三、第三阶段:微服务架构——精细化治理
为什么要进一步演进?
SOA架构解决了服务拆分的问题,但随着服务数量增加到几十个,新的问题出现了:
配置管理混乱:每个服务都有自己的配置文件,修改一个公共配置需要逐个修改
监控告警缺失:服务多了,不知道哪个服务出了问题
链路追踪困难:一个请求跨越多个服务,排查问题需要逐一看日志
技术选型
|
能力维度 |
技术组件 |
作用 |
|---|---|---|
|
配置中心 |
Nacos/Apollo |
统一管理配置,支持动态刷新 |
|
服务网关 |
Spring Cloud Gateway |
路由转发、限流、鉴权 |
|
链路追踪 |
SkyWalking |
全链路调用链追踪 |
|
监控告警 |
Prometheus + Grafana |
指标采集与可视化 |
|
容器化 |
Docker + Kubernetes |
自动化部署与弹性伸缩 |
微服务架构的收益
独立部署:每个服务可以独立发布,不影响其他服务
弹性伸缩:大促期间,只对订单服务和支付服务进行扩容,节省资源
故障隔离:某个服务宕机,不会影响整个系统的可用性
四、关键业务模块的设计要点
商品模块:SPU与SKU模型
纯文本纯文本SPU(Standard Product Unit):iPhone 14 Pro Max ├── SKU1:iPhone 14 Pro Max / 深空黑 / 256GB ├── SKU2:iPhone 14 Pro Max / 银色 / 256GB └── SKU3:iPhone 14 Pro Max / 深空黑 / 512GB
SPU是抽象的商品概念,SKU是具体的可售卖单元。商品详情页展示SPU信息,用户选择规格后确定具体的SKU。
订单模块:状态机设计
订单状态的流转必须严谨,不能出现状态跳跃或回退。推荐使用状态机模式:
纯文本纯文本待支付 → 已支付 → 已发货 → 已签收 → 已完成 ↓ ↓ ↓ ↓ 取消 退款 退货 售后
状态机的好处是:状态流转的逻辑集中在一个地方管理,避免了散落在各个业务代码中的if-else判断。
库存模块:分布式锁的选型
扣减库存是高并发场景下的核心操作。需要保证:同一时刻,只有一个线程能扣减某个SKU的库存。
|
方案 |
优点 |
缺点 |
|---|---|---|
|
数据库乐观锁 |
实现简单 |
并发性能差 |
|
Redis分布式锁 |
性能好 |
需处理锁超时 |
|
Redisson |
功能完善 |
增加依赖 |
实战建议:对于绝大多数场景,Redisson提供的分布式锁已经足够。它的看门狗机制可以自动续期,避免锁超时导致的数据不一致。
五、给Java商城系统开发者的建议
建议一:不要过度设计
创业初期,能用单体解决的问题就不要上微服务。过度设计会增加开发和维护成本,拖慢产品迭代速度。等到业务规模确实需要的时候,再进行架构升级。
建议二:重视测试
电商系统的容错率很低。一个支付bug可能导致资金损失,一个库存bug可能导致超卖。建立完善的测试体系:单元测试、集成测试、压测、混沌工程。
建议三:拥抱云原生
现在的Java商城系统,已经没有必要自己搭建机房。阿里云、腾讯云、AWS提供了丰富的云服务:RDS替代自建数据库、OSS替代自建文件存储、SLB替代自建负载均衡。把精力集中在业务逻辑上,而不是基础设施的维护上。
结语:
从一个Tomcat到几十个微服务,从一台MySQL到分库分表,Java商城系统的技术演进史,就是一部业务增长史。每一次架构升级的背后,都是业务规模的增长和技术团队的成长。
技术没有银弹,也没有一步到位的完美架构。唯一不变的是:永远为下一个阶段的增长做好准备。