毕业设计实战:Spring Boot无人智慧超市管理系统避坑指南
开发无人超市系统时,商品库存与订单的实时一致性曾是最大技术难题。初期未设计库存锁定机制,导致超卖现象频发——用户A下单瞬间,用户B仍可购买同一商品。我们耗时3天重构,通过Redis分布式锁+数据库悲观锁双重保障才解决此问题。
一、需求分析:聚焦无人超市核心场景
1. 用户角色与核心功能
用户端(购物者)
- 无感购物流程:扫码进店→选取商品→自助结算→无感支付
- 智能推荐:基于购买历史推荐商品
- 订单管理:实时查看订单状态、历史记录
管理员端(运营者)
- 商品智能管理:自动补货提醒、临期商品预警
- 实时监控:店内客流分析、热销商品统计
- 异常处理:订单异常、设备故障实时告警
2. 核心痛点识别
- 库存同步延迟:多用户同时购买最后一件商品
- 支付回调丢失:第三方支付成功但订单未更新
- 设备离线处理:扫码设备断网时交易如何保障
二、技术选型:稳定压倒一切
| 技术组件 | 选型理由 | 避坑提醒 |
|---|---|---|
| Spring Boot 2.7 | 快速开发,微服务友好 | 避免3.0版本,生态未完善 |
| Redis 6.0 | 库存缓存、分布式锁、会话管理 | 一定要配置持久化 |
| MySQL 8.0 | 事务支持,数据一致性 | 使用InnoDB引擎+行锁 |
| WebSocket | 实时推送订单状态 | 注意断线重连机制 |
| MinIO | 商品图片存储 | 访问权限严格控制 |
关键配置示例
spring:
redis:
host: localhost
port: 6379
timeout: 3000ms
lettuce:
pool:
max-active: 8 # 连接池大小按需调整
三、数据库设计:库存管理是核心
1. 关键表结构优化
-- 商品表(核心字段)
CREATE TABLE product (
id BIGINT PRIMARY KEY,
product_no VARCHAR(50) UNIQUE, -- 商品唯一编码
name VARCHAR(100),
price DECIMAL(10,2),
total_stock INT, -- 总库存
available_stock INT, -- 可用库存(实时更新)
lock_stock INT DEFAULT 0, -- 锁定库存(下单未支付)
status TINYINT DEFAULT 1, -- 1-上架 0-下架
INDEX idx_status_stock (status, available_stock)
);
-- 订单表
CREATE TABLE order_info (
id BIGINT PRIMARY KEY,
order_no VARCHAR(50) UNIQUE,
user_id BIGINT,
total_amount DECIMAL(10,2),
status TINYINT, -- 0-待支付 1-已支付 2-已完成 3-已取消
create_time DATETIME,
pay_time DATETIME,
INDEX idx_user_status (user_id, status)
);
-- 订单商品明细表
CREATE TABLE order_item (
id BIGINT PRIMARY KEY,
order_id BIGINT,
product_id BIGINT,
quantity INT,
price DECIMAL(10,2),
FOREIGN KEY (product_id) REFERENCES product(id)
);
2. 库存扣减核心逻辑
@Service
@Transactional
public class StockService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public boolean reduceStock(Long productId, Integer quantity) {
// 1. Redis分布式锁防止超卖
String lockKey = "stock_lock:" + productId;
String lockValue = UUID.randomUUID().toString();
try {
// 尝试获取锁(3秒超时)
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, lockValue, 3, TimeUnit.SECONDS);
if (!Boolean.TRUE.equals(locked)) {
throw new RuntimeException("系统繁忙,请重试");
}
// 2. 检查库存(Redis预检)
String stockKey = "product_stock:" + productId;
Long stock = redisTemplate.opsForValue().decrement(stockKey, quantity);
if (stock < 0) {
// 库存不足,回滚
redisTemplate.opsForValue().increment(stockKey, quantity);
return false;
}
// 3. 数据库实际扣减(悲观锁)
productMapper.reduceStockWithLock(productId, quantity);
return true;
} finally {
// 释放锁(Lua脚本保证原子性)
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(lockKey),
lockValue
);
}
}
}
3. 避坑要点
- 库存分离设计:总库存、可用库存、锁定库存分开管理
- 双重锁机制:Redis分布式锁+数据库行锁
- 超时处理:锁定库存15分钟未支付自动释放
四、功能实现:无人购物全流程
1. 核心模块一:扫码购物流程
- 进店扫码:生成唯一会话ID,记录进店时间
- 商品识别:RFID/图像识别/扫码三种方式
- 实时计算:购物车金额实时更新,支持优惠券
2. 核心模块二:智能结算系统
// 结算服务示例
public class SettlementService {
public SettlementResult calculate(Cart cart) {
// 1. 验证库存
cart.getItems().forEach(item -> {
if (!stockService.checkStock(item.getProductId(), item.getQuantity())) {
throw new StockNotEnoughException();
}
});
// 2. 计算金额
BigDecimal total = cart.getItems().stream()
.map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 3. 应用优惠
total = applyDiscount(total, cart.getCouponId());
// 4. 锁定库存
cart.getItems().forEach(item -> {
stockService.lockStock(item.getProductId(), item.getQuantity());
});
return new SettlementResult(total, cart.getItems());
}
}
3. 核心模块三:支付回调处理
- 支付成功:更新订单状态,扣减实际库存
- 支付失败:释放锁定库存,订单状态置为取消
- 支付超时:定时任务扫描15分钟未支付订单
五、系统测试:并发是重点
1. 压力测试场景
- 秒杀场景:100件商品,1000人同时抢购
- 支付回调:模拟第三方支付延迟和失败
- 设备断网:购物过程中网络中断处理
2. 测试工具推荐
- JMeter:模拟高并发请求
- Redis-benchmark:Redis性能测试
- MySQLslap:数据库压力测试
六、答辩准备:突出技术亮点
- 演示流程:用户扫码进店→选取商品→自助结算→离店扣款
- 技术难点:
- 如何解决超卖问题?(展示双重锁代码)
- 如何处理支付回调丢失?(幂等性设计)
- 如何保证数据一致性?(分布式事务方案)
- 扩展思考:
- 如何扩展到多店连锁?
- 如何集成人脸识别支付?
结语
无人超市系统的核心是实时性和可靠性。抓住库存管理、支付流程、异常处理三个关键点,你的毕设就能脱颖而出。
需要完整技术方案(含库存锁、支付回调处理)请留言"无人超市"获取。
记住:稳定比炫技更重要!🛒