核心模块
| 模块 | 功能 |
|---|---|
| 用户中心 | 注册、登录、个人信息 |
| 商品中心 | 商品管理、分类、SKU |
| 订单中心 | 下单、支付、退款 |
| 库存中心 | 库存管理、扣减、预占 |
| 支付中心 | 支付渠道、回调、对账 |
| 营销中心 | 优惠券、满减、秒杀 |
单体架构
├── app/
│ ├── Http/Controllers/
│ │ ├── UserController.php
│ │ ├── ProductController.php
│ │ ├── OrderController.php
│ │ └── PaymentController.php
│ ├── Models/
│ ├── Services/
│ └── Repositories/
├── database/
└── routes/
适用场景: 初创期,日订单 < 1 万
微服务架构
┌─────────────┐
│ Gateway │
└──────┬──────┘
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户服务 │ │ 商品服务 │ │ 订单服务 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
┌────▼─────┐ ┌────▼─────┐ ┌────▼─────┐
│ MySQL │ │ MySQL │ │ MySQL │
└──────────┘ └──────────┘ └──────────┘
数据库设计
用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
phone VARCHAR(20) UNIQUE,
password VARCHAR(255),
nickname VARCHAR(50),
avatar VARCHAR(255),
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
商品表
CREATE TABLE products (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(200),
category_id INT,
brand_id INT,
price DECIMAL(10,2),
market_price DECIMAL(10,2),
stock INT DEFAULT 0,
sales INT DEFAULT 0,
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_category (category_id),
INDEX idx_status_sales (status, sales)
);
CREATE TABLE product_skus (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT,
specs JSON,
price DECIMAL(10,2),
stock INT DEFAULT 0,
INDEX idx_product (product_id)
);
订单表
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(32) UNIQUE,
user_id BIGINT,
total_amount DECIMAL(10,2),
pay_amount DECIMAL(10,2),
discount_amount DECIMAL(10,2) DEFAULT 0,
status TINYINT DEFAULT 0,
pay_time TIMESTAMP NULL,
ship_time TIMESTAMP NULL,
finish_time TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user (user_id),
INDEX idx_status (status),
INDEX idx_created (created_at)
);
CREATE TABLE order_items (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT,
product_id BIGINT,
sku_id BIGINT,
product_name VARCHAR(200),
sku_specs JSON,
price DECIMAL(10,2),
quantity INT,
INDEX idx_order (order_id)
);
下单流程
1. 校验商品和库存
2. 计算价格(优惠券、满减)
3. 预扣库存
4. 创建订单
5. 发送延迟消息(超时取消)
6. 返回支付信息
代码实现
<?php
class OrderService
{
public function create(int $userId, array $items, ?int $couponId = null): Order
{
return DB::transaction(function () use ($userId, $items, $couponId) {
// 1. 校验商品
$products = $this->validateProducts($items);
// 2. 预扣库存
foreach ($items as $item) {
$locked = $this->inventoryService->lock(
$item['sku_id'],
$item['quantity']
);
if (!$locked) {
throw new Exception('库存不足');
}
}
// 3. 计算价格
$amounts = $this->calculateAmount($products, $items, $couponId);
// 4. 创建订单
$order = Order::create([
'order_no' => $this->generateOrderNo(),
'user_id' => $userId,
'total_amount' => $amounts['total'],
'discount_amount' => $amounts['discount'],
'pay_amount' => $amounts['pay'],
'status' => OrderStatus::PENDING
]);
// 5. 创建订单项
foreach ($items as $item) {
$product = $products[$item['product_id']];
OrderItem::create([
'order_id' => $order->id,
'product_id' => $item['product_id'],
'sku_id' => $item['sku_id'],
'product_name' => $product->name,
'price' => $product->price,
'quantity' => $item['quantity']
]);
}
// 6. 发送延迟消息
$this->mq->publishDelayed('order_timeout', [
'order_id' => $order->id
], 30 * 60 * 1000);
return $order;
});
}
private function generateOrderNo(): string
{
return date('YmdHis') . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT);
}
}
库存扣减
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 下单减库存 | 简单 | 恶意下单占库存 |
| 支付减库存 | 不占库存 | 超卖风险 |
| 预扣库存 | 平衡 | 实现复杂 |
预扣库存实现
<?php
class InventoryService
{
// 预扣库存
public function lock(int $skuId, int $quantity): bool
{
$key = "inventory:lock:{$skuId}";
// Lua 脚本保证原子性
$script = <<<LUA
local stock = redis.call('hget', KEYS[1], 'stock')
local locked = redis.call('hget', KEYS[1], 'locked')
if tonumber(stock) - tonumber(locked) >= tonumber(ARGV[1]) then
redis.call('hincrby', KEYS[1], 'locked', ARGV[1])
return 1
end
return 0
LUA;
return (bool) Redis::eval($script, 1, $key, $quantity);
}
// 确认扣减(支付成功)
public function confirm(int $skuId, int $quantity): void
{
$key = "inventory:lock:{$skuId}";
Redis::hincrby($key, 'stock', -$quantity);
Redis::hincrby($key, 'locked', -$quantity);
// 同步到数据库
ProductSku::where('id', $skuId)->decrement('stock', $quantity);
}
// 释放库存(取消/超时)
public function release(int $skuId, int $quantity): void
{
$key = "inventory:lock:{$skuId}";
Redis::hincrby($key, 'locked', -$quantity);
}
}
订单状态机
待支付 ──支付成功──▶ 已支付 ──发货──▶ 已发货 ──确认收货──▶ 已完成
│ │
│超时/取消 │退款
▼ ▼
已取消 已退款
<?php
class OrderStatus
{
const PENDING = 0; // 待支付
const PAID = 1; // 已支付
const SHIPPED = 2; // 已发货
const COMPLETED = 3; // 已完成
const CANCELLED = 4; // 已取消
const REFUNDED = 5; // 已退款
public static function canTransition(int $from, int $to): bool
{
$transitions = [
self::PENDING => [self::PAID, self::CANCELLED],
self::PAID => [self::SHIPPED, self::REFUNDED],
self::SHIPPED => [self::COMPLETED, self::REFUNDED],
];
return in_array($to, $transitions[$from] ?? []);
}
}
总结
| 模块 | 关键点 |
|---|---|
| 商品 | SKU 设计、库存同步 |
| 订单 | 状态机、幂等性 |
| 库存 | 预扣机制、Redis + DB |
| 支付 | 异步回调、对账 |
电商系统是综合性很强的项目,后续会深入讲解支付、秒杀等模块。