You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

宴会厅宾客座位管理系统并发问题求解(API+MySQL架构)

用MySQL数据库约束解决宴会厅座位并发超配问题

核心思路

通过数据库层面的事务原子性、行级锁和约束校验,从根源上避免并发请求导致的餐桌容量超配问题,无需依赖API层的前置校验(前置校验在并发场景下天然不可靠)。


第一步:数据库表结构设计

必须使用InnoDB引擎(支持事务和行锁),设计两张核心表:

1. 餐桌表(tables)

存储餐桌固定容量,并通过CHECK约束保证当前占用人数不超上限:

CREATE TABLE tables (
    table_id INT PRIMARY KEY AUTO_INCREMENT,
    capacity INT NOT NULL CHECK (capacity > 0),
    current_occupancy INT DEFAULT 0 CHECK (current_occupancy <= capacity)
) ENGINE=InnoDB;

2. 宾客座位表(guest_seats)

记录宾客座位信息,关联对应餐桌:

CREATE TABLE guest_seats (
    seat_id INT PRIMARY KEY AUTO_INCREMENT,
    table_id INT NOT NULL,
    guest_name VARCHAR(100) NOT NULL,
    companion_count INT NOT NULL CHECK (companion_count >= 0),
    FOREIGN KEY (table_id) REFERENCES tables(table_id) ON DELETE CASCADE,
    INDEX idx_table_id (table_id)
) ENGINE=InnoDB;

第二步:并发安全的添加宾客方案

方案1:行锁+事务(推荐,性能稳定)

通过SELECT ... FOR UPDATE锁定目标餐桌行,确保同一时间只有一个请求能修改该餐桌的占用状态,整个操作在事务中完成:

START TRANSACTION;

-- 锁定目标餐桌,禁止其他并发请求修改
SELECT capacity, current_occupancy 
FROM tables 
WHERE table_id = ? -- 替换为目标餐桌ID
FOR UPDATE;

-- 计算需要占用的总人数(宾客1人 + 随行友人数量)
SET @total_people = 1 + ?; -- 替换为随行人数

-- 校验剩余容量,满足则执行更新和插入
IF (SELECT (capacity - current_occupancy) >= @total_people FROM tables WHERE table_id = ?) THEN
    -- 更新餐桌当前占用数
    UPDATE tables 
    SET current_occupancy = current_occupancy + @total_people 
    WHERE table_id = ?;

    -- 插入宾客记录
    INSERT INTO guest_seats (table_id, guest_name, companion_count)
    VALUES (?, ?, ?); -- 替换为餐桌ID、宾客姓名、随行人数

    COMMIT;
ELSE
    -- 容量不足,回滚事务
    ROLLBACK;
END IF;

API层只需判断事务是否提交成功:若提交失败(触发CHECK约束报错),则返回"容量不足"提示。

方案2:触发器自动维护占用数 + 插入条件校验

若不想手动维护current_occupancy,可通过触发器自动计算,同时在插入宾客时直接校验容量:

第一步:创建触发器自动更新占用数
-- 插入宾客后更新餐桌占用数
DELIMITER //
CREATE TRIGGER trg_update_occupancy_after_insert
AFTER INSERT ON guest_seats
FOR EACH ROW
BEGIN
    UPDATE tables 
    SET current_occupancy = current_occupancy + (1 + NEW.companion_count)
    WHERE table_id = NEW.table_id;
END //
DELIMITER ;

-- 删除宾客后更新餐桌占用数
DELIMITER //
CREATE TRIGGER trg_update_occupancy_after_delete
AFTER DELETE ON guest_seats
FOR EACH ROW
BEGIN
    UPDATE tables 
    SET current_occupancy = current_occupancy - (1 + OLD.companion_count)
    WHERE table_id = OLD.table_id;
END //
DELIMITER ;
第二步:原子性插入宾客(带容量校验)
INSERT INTO guest_seats (table_id, guest_name, companion_count)
SELECT ?, ?, ? -- 替换为餐桌ID、宾客姓名、随行人数
FROM tables
WHERE table_id = ?
AND (capacity - (SELECT COALESCE(SUM(1 + companion_count), 0) FROM guest_seats WHERE table_id = ?)) >= (1 + ?);
  • 若插入行数为0,说明容量不足,API层直接返回错误提示。
  • 此方式无需手动管理事务,MySQL会自动保证插入操作的原子性。

关键注意事项

  1. 必须使用InnoDB引擎:MyISAM不支持事务和行级锁,无法解决并发问题。
  2. 缩短事务时长:SELECT ... FOR UPDATE会锁定行,事务时间越长,并发阻塞越严重,尽量精简操作步骤。
  3. 版本兼容:CHECK约束在MySQL 8.0.16及以上版本才生效,低版本需用触发器替代校验逻辑。

内容的提问来源于stack exchange,提问作者daniel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:45:00