CodeGym /课程 /SQL SELF /订单处理的综合流程示例:数据校验、状态更新、日志记录

订单处理的综合流程示例:数据校验、状态更新、日志记录

SQL SELF
第 54 级, 课程 0
可用

今天我们来拆解一个真实的订单处理流程。它分好几个步骤:数据校验、订单状态更新,还有日志记录。想象一下在餐厅,厨师、服务员和收银员得配合好。我们这个流程其实就是把这些环节的逻辑串起来。

流程需求描述

订单处理流程要做这些事:

  1. 检查仓库里有没有需要的商品。
  2. 如果库存够,就从仓库里扣掉数量。
  3. 把订单状态改成“已处理”。
  4. 把成功的信息写进日志表。
  5. 如果出错了,所有操作都要回滚。

流程实现

第1步:建表和准备数据结构

写流程前,先建好要用的表。

orders 表 — 订单

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer_name TEXT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL CHECK (quantity > 0),
    status TEXT DEFAULT 'Pending'
);

这个表存订单。每个订单有客户、产品ID、数量和状态(默认“待处理”)。

inventory 表 — 仓库

CREATE TABLE inventory (
    product_id SERIAL PRIMARY KEY,
    product_name TEXT NOT NULL UNIQUE,
    stock INT NOT NULL CHECK (stock >= 0)
);

仓库商品表。每个产品有当前库存(stock)。

order_logs 表 — 操作日志

CREATE TABLE order_logs (
    log_id SERIAL PRIMARY KEY,
    order_id INT NOT NULL REFERENCES orders(order_id) ON DELETE CASCADE,
    log_message TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

日志表用来记录订单处理的状态信息。

第2步:流程结构

多步骤流程的结构如下:

  1. 查查仓库有没有要的商品,数量够不够。
  2. 如果库存够,就在inventory表里减掉数量。
  3. 把订单状态改成“已处理”。
  4. 把成功结果写进order_logs表。
  5. 遇到错误就回滚。

第3步:写流程

来写个process_order流程,按上面说的步骤来。

CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS VOID AS $$
DECLARE
    v_product_id INT;
    v_quantity INT;
    v_stock INT;
BEGIN
    -- 第1步:查订单信息
    SELECT product_id, quantity
    INTO v_product_id, v_quantity
    FROM orders
    WHERE order_id = $1;

    -- 检查订单是否存在
    IF NOT FOUND THEN
        RAISE EXCEPTION '订单ID % 不存在。', $1;
    END IF;

    -- 第2步:查仓库库存
    SELECT stock INTO v_stock
    FROM inventory
    WHERE product_id = v_product_id;

    IF NOT FOUND THEN
        RAISE EXCEPTION '产品ID % 在仓库里找不到。', v_product_id;
    END IF;

    IF v_stock < v_quantity THEN
        RAISE EXCEPTION '产品ID % 库存不足。需要: %, 可用: %。',
            v_product_id, v_quantity, v_stock;
    END IF;

    -- 第3步:扣减库存
    UPDATE inventory
    SET stock = stock - v_quantity
    WHERE product_id = v_product_id;

    -- 第4步:把订单状态改成“已处理”
    UPDATE orders
    SET status = 'Processed'
    WHERE order_id = $1;

    -- 第5步:写日志,记录成功
    INSERT INTO order_logs (order_id, log_message)
    VALUES ($1, '订单处理成功。');

EXCEPTION
    WHEN OTHERS THEN
        -- 任何失败都写日志
        INSERT INTO order_logs (order_id, log_message)
        VALUES ($1, '订单处理出错: ' || SQLERRM);

        -- 回滚所有操作
        RAISE;
END;
$$ LANGUAGE plpgsql;

我们来拆解下这个流程。

  1. 校验阶段:

    先查orders表里有没有这个订单。如果没有,就抛出详细异常。同理,查仓库有没有这个产品和库存够不够。

  2. 仓库操作阶段:

    库存够就直接UPDATE扣减。

  3. 订单状态变更阶段:

    把状态改成“Processed”(已处理),表示订单搞定了。

  4. 日志记录阶段:

    订单处理成功后,往order_logs表里插入一条记录。

  5. 异常处理:

    如果哪里出错了,在EXCEPTION块里捕获,写详细错误日志,然后回滚所有操作。

使用示例

我们来造点测试数据,看看流程效果。

-- 往仓库加点商品
INSERT INTO inventory (product_name, stock)
VALUES ('Laptop', 10), ('Monitor', 5);

-- 加点订单
INSERT INTO orders (customer_name, product_id, quantity)
VALUES
    ('Alice', 1, 2),
    ('Bob', 2, 1),
    ('Charlie', 1, 20); -- 这个订单应该会报错

现在来测试下流程:

-- 处理Alice的订单
SELECT process_order(1);

-- 处理Bob的订单
SELECT process_order(2);

-- 试试处理Charlie的订单(会报错)
SELECT process_order(3);

结果:

  • Alice和Bob的订单会处理成功,写进日志,仓库库存也会减少。
  • Charlie的订单因为库存不够会报错,日志里会有错误记录。

处理完后查下表:

SELECT * FROM inventory; -- 看库存变化
SELECT * FROM orders; -- 看订单状态
SELECT * FROM order_logs; -- 看日志记录

常见错误和建议

  1. 错误:SELECT INTO后忘了检查NOT FOUND。

    一定要处理查不到数据的情况,不然会有奇怪的异常。

  2. 错误:没写EXCEPTION块。

    流程里没写异常处理的话,出错时事务可能卡住或者流程乱套。

  3. 建议:防SQL注入。

    用强类型参数,没必要别用动态SQL。

流程扩展

实际项目里可以加更多校验,比如:

  • 考虑客户的折扣或促销。
  • 处理订单前查下客户信用额度。
  • 不仅记录成功,还要记录回滚操作。
2
任务
SQL SELF, 第 54 级, 课程 0
已锁定
订单处理过程
订单处理过程
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION