JavaWeb项目实战|Java 实战项目

从“手艺人”的笨功夫出发,用真实项目场景重构认知:不谈空泛理论,只讲落地细节。库存管理、订单系统、高并发、服务降级、链路追踪……在这里,每个技术点都带着血和汗的教训。

立即开启实战之旅 →

后端开发的第一性原理:先做出来,再做好

别被“架构模式”吓退——真正的成长,始于第一个能跑通的接口。

先跑通,再优化

刚搭好 Spring Boot 的脚手架,我第一反应不是翻文档,而是直接扔进 IDEA 敲代码。你可能会说这太“野路子”,但实战中——能跑通的代码才是活代码

? 小技巧:用 Swagger 快速生成接口文档,再拷贝参数到 Postman 跑通——这一步看似简单,实则帮你绕过环境配置的“微秒级卡顿”,快速进入业务逻辑验证。

拥抱“笨功夫”

我见过太多人把项目做得像论文一样精致,结果上线那天就像孤儿院——没人管、没人懂、没人修。真正的高手,懂得用“笨办法”打基础:日志打满、断言前置、异常显性化。

⚠️ 注意:别嫌日志乱码——哪怕乱码,它也是你排查问题的“时间戳锚点”。比起完美日志,及时性更重要。

拒绝“纸上谈兵”

别老跟我提“面向对象”要么“面向过程”——那是给硕士论文预备的。在真实业务里,我更喜欢:数组当数组,字符串当字符串。

// 库存管理:直接用基础结构 List<Integer> skuIds = Arrays.asList(1001, 1002, 1003); Map<String, Integer> stockMap = new HashMap<>(); stockMap.put("1001", 50); stockMap.put("1002", 0); // 库存为0,触发降级逻辑

为什么“先做出来”反而更高效?

  • ✅ 快速验证业务假设,避免“想太多、写太少”
  • ✅ 暴露真实技术债(如数据库连接池配置不足)
  • ✅ 建立“可运行”的最小闭环,为后续重构提供支点
  • ✅ 团队协作时,有代码可跑,沟通成本直降

电商订单系统:从“能用”到“好用”的跨越

以一个简易电商订单系统为例,初期我们只实现:用户下单 → 库存扣减 → 订单生成 → 支付回调。但上线后发现,高并发下库存超卖频发。

解决方案不是立刻上分布式事务,而是先做三件事:

  • 数据库层面:订单表加唯一索引(用户ID+商品ID)
  • 代码层:用 SELECT ... FOR UPDATE 锁行,而非锁表
  • Redis 预减库存:下单前先在 Redis 中预扣库存,失败则直接返回“库存不足”
public String createOrder(Long userId, Long skuId) { // 先预扣 Redis 库存 if (!redisTemplate.opsForValue().increment("stock:" + skuId, -1) >= 0) { return "库存不足"; } // 再查数据库并加锁 synchronized (this.getClass().getName().getBytes()) { int realStock = orderMapper.getStockForUpdate(skuId); if (realStock <= 0) { return "库存不足"; } orderMapper.decreaseStock(skuId); return "下单成功"; } }

库存管理的三个致命误区

很多开发者以为库存就是简单减一,但真实场景中,以下问题频发:

  • ⚠️ 超卖:未加锁或锁粒度太大(如锁整个表)
  • ⚠️ 库存回滚失败:订单取消后 Redis 已扣减但 DB 未回滚
  • ⚠️ 缓存穿透:大量请求查不存在的商品ID,直接打穿 DB

缓存穿透解决方案

  • 对空结果缓存(设置短 TTL,如 5 分钟)
  • 布隆过滤器拦截非法 ID
  • 缓存预热:上线前加载高频商品库存

开发节奏误区:别让“完美主义”拖垮项目

我见过一个项目,需求评审后花两周画 UML 图、画类图、画时序图……最后上线时,需求早已过时。

真正的节奏应该是:

  1. Day 1:跑通最小流程(如“查看商品 → 加入购物车”)
  2. Day 3:补全核心链路(下单 → 支付 → 库存扣减)
  3. Day 7:补日志、加监控、做压测
  4. Day 14:优化性能、加幂等、做降级
? 记住:上线不是终点,而是反馈循环的起点。活下来的项目,才有资格谈“架构演进”。

数据结构:后端开发的“肌肉记忆”

在千万级订单量面前,优雅的模型不如一行高效的数据处理。

核心原则:用对的结构,解决对的问题

别迷信“面向对象万能论”——在高频调用的接口中,性能优先于抽象

数组 vs 集合

比如秒杀活动中的“用户抢购记录”,初期用 List 存储所有用户ID,但压测发现内存爆炸——每个请求都创建新 List。

优化方案:改用 ConcurrentHashMap<Long, Boolean>,值只存 true 表示已抢购。

private ConcurrentHashMap<Long, Boolean>抢购记录 = new ConcurrentHashMap<>(); public boolean recordPurchase(long userId) { return 抢购记录.putIfAbsent(userId, true) == null; }

Map 的妙用

库存管理中,别用对象封装再操作——直接用 Map<String, Integer> 存 SKU-ID 与库存映射,查询效率提升 3 倍以上。

? 原因:避免了对象创建开销 + JVM 内存对齐损耗 + GC 压力。

队列的异步解耦

订单创建后,需发短信、扣库存、记日志——这些非核心操作,别同步执行!改用 LinkedBlockingQueue 或 RocketMQ 异步消费。

// 生产者 orderEventQueue.offer(new OrderCreatedEvent(orderId)); // 消费者线程(常驻) new Thread(() -> { while (true) { OrderCreatedEvent event = orderEventQueue.take(); smsService.send(event.getOrderId()); inventoryService.decrease(event.getSkuId()); } }).start();

初期:所有操作同步执行,用户反馈“下单慢”

优化1:库存扣减改用 Redis 预减 + Lua 脚本保证原子性

优化2:日志、短信异步化,主流程耗时从 850ms → 120ms

优化3:引入事件总线(Spring Event),解耦更彻底

服务稳定性:比功能上线更重要

稳定性不是“不出错”,而是“错了也能扛住”。

稳住,我们能赢——三个关键防线

  • ?️ 第一道防线:参数校验(前端 + 后端双校验)
  • ?️ 第二道防线:数据库连接池监控(HikariCP 配置合理)
  • ?️ 第三道防线:线程池隔离(核心业务与非核心业务线程池分离)

ThreadLocal 的正确打开方式

很多项目在 Controller 层用 ThreadLocal 存用户信息,但忘记 remove()——导致线程复用时,A 用户看到 B 用户数据!

public class UserContext { private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>(); public static void setCurrentUser(User user) { userThreadLocal.set(user); } public static User getCurrentUser() { return userThreadLocal.get(); } public static void clear() { userThreadLocal.remove(); // 必须! } }
⚠️ 建议:在 @Around 切面中统一 clear(),避免遗漏。

数据库锁的避坑指南

库存扣减时,若用 SELECT ... FOR UPDATE,记得:
① 必须在事务中执行;
② 索引字段必须加索引(否则锁表);
③ 避免长事务导致锁等待。

@Transactional(rollbackFor = Exception.class) public void decreaseStock(Long skuId) { // 必须加 WHERE id = ? AND stock > 0 int updated = stockMapper.decreaseStockById(skuId); if (updated == 0) { throw new RuntimeException("库存不足"); } }

断言前置化

别让错误在深层调用中才抛出!在方法入口处就校验参数:空值、范围、状态合法性。

public Order createOrder(OrderRequest req) { Assert.notNull(req.getUserId(), "用户ID不能为空"); Assert.notNull(req.getSkuId(), "商品ID不能为空"); Assert.state(req.getQuantity() > 0, "数量必须大于0"); Assert.state(stockService.hasStock(req.getSkuId(), req.getQuantity()), "库存不足"); // 真正业务逻辑... }

日志:不是“打印一下”,而是“构建线索”

好的日志应包含:
• 时间戳(精确到毫秒)
• 请求ID(全链路追踪)
• 用户ID(可选脱敏)
• 关键参数
• 操作结果(成功/失败/异常)
• 耗时

示例:
[2024-05-10 14:23:01.567] [req-abc123] [user=8827] createOrder skuId=1001 qty=2 cost=120ms SUCCESS

兜底策略:高可用的最后一道防线

当服务挂了,别让用户看到“500 错误”——用降级策略守住体验底线。

订单创建接口:三重兜底方案

  1. 重试机制:调用失败后重试 2 次(间隔 200ms),避免瞬时故障
  2. 节点切换:若主库挂了,自动切换到从库(读写分离)
  3. 降级记录:若仍失败,将订单信息写入 Redis 队列 + DB 日志表,异步补单
@HystrixCommand(fallbackMethod = "createOrderFallback") public String createOrder(OrderRequest req) { return orderService.realCreateOrder(req); } public String createOrderFallback(OrderRequest req, Throwable e) { // 写入降级队列 fallbackQueue.offer(req); return "系统繁忙,订单已记录,请稍后查看"; }

支付回调:防止重复扣款

微信/支付宝回调时,必须做三件事:
① 查本地订单状态(是否已支付)
② 校验签名
③ 更新状态 + 发通知

public String handlePayCallback(PayNotify notify) { Long orderId = notify.getOrderId(); Order order = orderMapper.selectById(orderId); if (order == null) { return "订单不存在"; } if ("PAID".equals(order.getStatus())) { return "已处理"; // 幂等! } if (!verifySign(notify)) { throw new RuntimeException("签名验证失败"); } order.setStatus("PAID"); orderMapper.updateById(order); return "SUCCESS"; }

Hystrix 熔断 + Sentinel 限流

核心接口必须配置熔断策略:
• 请求失败率 > 50% → 熔断 30 秒
• 每秒请求数 > 100 → 限流(拒绝或排队)

Sentinel 规则示例

  • 资源名:/api/order/create
  • 阈值类型:QPS
  • 阈值:100
  • 流控模式:直接拒绝
  • 熔断策略:慢调用比例 > 0.5 → 熔断 10s

数据驱动:让指标说话

别信直觉——用数据定位瓶颈,才是工程师的科学精神。

压测前必问自己三个问题

  • 数据库连接池大小是否匹配峰值 QPS?
  • Redis 内存是否够撑住热点数据?
  • 磁盘 I/O 是否成为瓶颈?(通过 iostat -x 1 查看 %util)

秒杀场景:Redis 内存优化

活动前,用 INFO memory 查 Redis 内存使用。若发现 used_memory_peak_human 接近上限,立即扩容或优化数据结构。

? 实战技巧:库存用 String 存("100"),而非 Hash——减少元数据开销。

慢查询分析

开启 MySQL 慢查询日志(slow_query_log=ON),定位耗时 > 1s 的 SQL。

常见问题:
• 未走索引(EXPLAIN 查看)
• JOIN 表过多
• SELECT 导致回表

-- 示例:优化前 SELECT FROM orders WHERE user_id = 12345; -- 优化后:只查必要字段 + 加索引 ALTER TABLE orders ADD INDEX idx_user (user_id); SELECT order_id, status, create_time FROM orders WHERE user_id = 12345;

监控指标:看板必备

接入 Prometheus + Grafana,监控以下核心指标:
• 请求 QPS / P99 / P999
• 错误率(HTTP 5xx)
• JVM 堆内存使用
• 数据库连接池活跃数
• Redis 命中率

压测前

日志显示:订单创建接口 P99 = 1200ms,错误率 5%

定位问题

通过 Arthas 监控,发现 orderMapper.insert 耗时 800ms+

根因分析

数据库索引缺失 + 事务过大(包含 3 个表操作)

优化后

P99 = 180ms,错误率 < 0.1%

API 幂等性:高并发下的“定心丸”

哪怕张三重复点击 10 次“提交”,系统也必须只生成一张订单。

幂等设计三原则

  • ✅ 所有写接口必须幂等(非 GET/HEAD/OPTIONS)
  • ✅ 用业务幂等键(如订单号、支付流水号)做去重
  • ✅ 优先用数据库唯一约束,其次用 Redis 分布式锁

订单创建:用 Redis 分布式锁

public String createOrder(OrderRequest req) { String lockKey = "order_lock:" + req.getUserId() + ":" + req.getSkuId(); Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS); if (!isLocked) { return "请求过于频繁,请稍后重试"; } try { // 真正下单逻辑 ... } finally { redisTemplate.delete(lockKey); } }

支付回调:用数据库唯一索引

在支付记录表中加唯一索引:UNIQUE KEY uk_transaction_no (transaction_no),重复回调时数据库自动拒绝。

INSERT INTO pay_records (order_id, transaction_no, amount, status) VALUES (1001, "WX20240510...", 99.00, "SUCCESS") ON DUPLICATE KEY UPDATE status = "DUPLICATE";

乐观锁防超卖

库存更新时加版本号:UPDATE stock SET stock=stock-1, version=version+1 WHERE id=1001 AND version=5,更新失败则重试。

常见幂等错误案例

  • ❌ 未校验重复提交(前端按钮重复点击)
  • ❌ 未处理网络超时重试(客户端重发请求)
  • ❌ 未考虑服务重试(如 Feign 默认重试 1 次)

软删除:对象存储中的“时间旅行”

用户删文件 ≠ 对象存储立即删——这背后藏着数据一致性难题。

为什么不能直接删?

对象存储(如 OSS/S3)采用 CC(并发控制)机制:删除后,若已有请求正在读取,仍需返回旧数据。直接物理删除会导致:
• 用户看到 404 错误
• 下载链接失效(但用户可能已保存链接)

步实现安全软删除

  1. 逻辑标记:在数据库表中加 is_deleted TINYINT(1) DEFAULT 0
  2. 查询过滤:所有 SELECT 加 WHERE is_deleted = 0
  3. 异步清理:定时任务检查,30 天后真正调用 OSS 删除 API
// 业务层:查询时自动过滤 public List<File> listFiles(Long userId) { return fileMapper.selectByUserId(userId); // 对应 SQL: SELECT FROM file WHERE user_id = ? AND is_deleted = 0 } // 删除接口:只标记 public void deleteFile(Long fileId) { fileMapper.updateIsDeleted(fileId, 1); // is_deleted = 1 }

OSS 生命周期规则配置

在对象存储控制台配置:
• 前缀:deleted/(或用标签 status=deleted
• 过期时间:30 天后自动删除

这样,即使数据库标记为删除,OSS 仍保留文件 30 天——既满足业务需求,又规避合规风险。

? 实战建议:在删除接口中,将文件移至 deleted/ 目录,并更新数据库 storage_path

调试技巧:把黑盒变成白盒

好代码自己会说话——日志要能定位到“第几行代码出错”。

打印日志的黄金法则

  • ✅ 打印实体对象(而非字符串拼接):log.info("用户登录: {}", user);
  • ✅ 业务状态码必须显式打印:如 status=PAIDcode=STOCK_NOT_ENOUGH
  • ✅ 关键路径加耗时:如 cost=120ms

日志示例对比

// ❌ 错误示范 log.info("下单失败"); // ✅ 正确示范 log.warn("下单失败: userId={}, skuId={}, code=STOCK_NOT_ENOUGH, cost={}ms", userId, skuId, 120);

Arthas 实时诊断

线上问题定位神器:
• 监控方法耗时:monitor -c 5 com.example.OrderController createOrder
• 查看方法入参:watch com.example.OrderController createOrder '{params, returnObj}'

日志分级策略

级别 用途 示例
ERROR系统异常(需人工介入)数据库连接失败、支付回调签名错误
WARN异常但可恢复库存不足、用户重复提交
INFO关键业务节点订单创建成功、用户登录
DEBUG开发调试SQL 执行详情、缓存命中情况

压测经验:上线前的“压力测试”

别等用户发现bug——在测试环境把问题都暴露出来。

压测三板斧

  • JMeter / Locust 模拟真实流量(登录 → 浏览 → 下单 → 支付)
  • 持续压测 1 小时以上,观察资源曲线是否稳定
  • 突发流量测试:50% → 200% QPS 瞬间突增

压测场景设计

  • ? 场景1:所有用户同时点“提交” → 测试订单服务峰值
  • ? 场景2:所有用户同时请求支付 → 测试第三方接口限流
  • ? 场景3:库存超卖测试 → 验证库存扣减逻辑
  • ? 场景4:缓存穿透测试 → 高频查询不存在的商品

压测结果分析

重点关注:
• CPU 使用率(>80% 需优化)
• 内存泄漏(GC 频繁?)
• 数据库连接池耗尽
• 错误率是否 > 0.1%

? 工具推荐:top + htop + jstat -gcutil 1000

压测后必做三件事

  1. ✅ 优化慢 SQL(加索引 / 拆分大查询)
  2. ✅ 调整线程池大小(核心线程数 = CPU 核心数 × 2)
  3. ✅ 设置合理超时(连接超时 200ms,读超时 1000ms)
◆ 最新
漳浦县人民政府项目-漳浦县贫困县帮扶项目新产品项目启动方案模板-新产品项目启动模板项目攻坚方案-项目攻坚方案地推项目平台有哪些-地推项目平台概览测试项目有哪些-测试项目有哪些北京欢乐谷项目-北京欢乐谷项目3518加盟网加工好项目-加盟网加工好项目列表齐市妇科检查项目及费用-齐市妇科检查全项目及费用ssm项目整合搭建-ssm 项目整合搭建如何做大项目-如何做大项目电气高压试验项目-电气高压试验项目容易挣钱的项目-赚钱的好项目世界运动会项目-世界运动会项目楼盘项目三亚-三亚楼盘项目中建七局近期中标项目有哪些-中建七局近期中标项目区块链国外优质项目-境外优质区块链项目全脑教育项目办公室-全脑教育项目办网赚项目资源共享-网赚项目资源共享成都老房改造项目-成都老房改造项目婚检需要做哪些检查项目-婚检主要检查项目五子棋游戏项目描述-五子棋项目描述园林绿化项目经理等级-园林项目经理等级公装公司招项目经理-公装公司招项目经理java毕业设计项目-Java 毕业项目net源码项目-免费源码项目项目管理考试 经验-项目管理经验介绍工程项目论证与评估的共同之处包括-工程论证与评估共同点黄岛主项目靠谱吗-黄岛项目是否靠谱项目融资风险有哪些-项目融资主要风险山东特色餐饮项目加盟-山东特色餐饮项目加盟idea maven项目分层-idea maven 项目分层医用防护服有哪些项目-医用防护服分类项目电动汽车充电桩项目计划书-充电桩项目计划书(10 字内)天天赚钱的项目-天天赚钱的项目招生宣传广告采购项目-招生宣传广告采购bim在工程项目的应用- BIM 在工程领域应用epc项目什么意思-EPC 项目指总承包。项目负责人撤出申请表空手套白狼灰色项目-空手套白狼灰色项目系统集成项目管理软件-集成项目管理软件汽车20000公里保养项目-汽车保养 20000 公里spa前列腺保养服务项目-SPA 前列腺保养项目vr创业项目有什么信息系统项目管理师第四版电子版-信息系统项目管理师第四版小加盟项目好-加盟项目好开启物业项目负责人培训考试简单吗?-培训考试难不难项目概述揭阳石油化工项目html5 项目设计实训男科常规检查都有哪些项目-男科常规检查项目项目加盟多少钱-项目加盟费用参考信息化项目立项申报书-立项申报书甘肃扶贫项目-甘肃扶贫项目建造师当项目经理-建造师任项目经理保健项目有哪些-保健项目有哪些国内平面设计公司项目-国内平面设计公司项目温州妇科检查项目费用-温州妇科检查费为老人服务的创业项目-老人服务项目创业建设项目党建联建口号-建设党建联建新成效蛋糕加盟项目-蛋糕加盟项目优化微商创业项目怎么找-微商创业项目如何寻迪士尼的各个项目-迪士尼项目系列项目资金审批程序-项目资金审批流程什么投资项目比较-投资项目筛选电商小投资项目-小项目投资机会新项目融资-新项目融资方案o2o农业创业项目-线上农商电商平台轻钢龙骨检测项目-轻钢龙骨检测项目工地项目经理很花心吗-项目经理花心吗热门创业好项目-热门创业好项目2019年互联网项目-2019 年项目用词脑电波检查项目-脑电波检测项目国外考察项目要素-考察项目主要要素岱山县鱼山岛石化项目-岱山鱼山石化项目高中生发明专利项目-中学生发明专利机械项目经理许海峰-机械项目经理许海峰如何关闭电脑启动项目-关闭电脑启动项目共享项目的商业计划书-共享项目商业计划书项目申请报告评审-项目评估与审批工程项目预算培训-工程项目预算培训建设项目运营-建设项目运营怎样做好施工项目经理-做好施工项目经理法分销系统项目-分销系统项目最新代理项目-最新代理项目血液检查项目多少钱-血液检查项目多少物业公司高端项目综合运营方案-高端物业运营综合方案工程项目风险管理规划-工程项目风险管控规划工程项目三公费用-工程项目三公费用迈德思客汉堡加盟项目-迈德思客汉堡加盟好的网络投资项目-信赖优质网络投资2018好项目开个什么厂-2018 年选对厂址项目医学影像包括哪些项目-医学影像包含诸多项目spring mvc 项目-SpringMVC 项目重构2011年致富项目-2011 年致富项目一般妇科检查什么项目-妇科检查常规项目时时彩团队计划项目-时时彩团队计划项目名尚赫减肥项目-尚赫减肥项目生活中的项目有哪些-生活项目大集合小程序项目发布会-小程序项目发布会
瑞秋资讯
蜀ICP备2026006976号-18