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

PostgreSQL 11办公工位预订系统避免重复插入方案咨询

PostgreSQL 11 工位预订系统:避免重复预订的可靠方案

核心思路:数据库约束 + 原子化插入逻辑

先查后插的逻辑在高并发场景下存在竞态漏洞(两个请求同时通过查询校验,随后同时插入导致重复数据)。最可靠的方案是用数据库唯一约束做底层兜底,再通过PL/pgSQL函数封装原子化插入逻辑,处理冲突并返回明确结果。

1. 完善表结构与约束

首先给预订表添加唯一约束,从数据库层面强制遵守预订规则:

-- 创建预订表(若未创建)
CREATE TABLE workstation_booking (
  id SERIAL PRIMARY KEY,
  booked_date DATE NOT NULL,
  seat_id INT NOT NULL,
  employee_id INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 添加两个唯一约束,分别实现两条规则
ALTER TABLE workstation_booking
ADD CONSTRAINT uq_employee_day UNIQUE (booked_date, employee_id), -- 每人每日仅能预订一个工位
ADD CONSTRAINT uq_seat_day UNIQUE (booked_date, seat_id); -- 工位每日不可重复预订

这两个约束是数据一致性的最后防线,任何违反规则的插入都会被数据库直接拦截。

2. 用PL/pgSQL函数封装插入逻辑

编写PL/pgSQL函数,将插入操作原子化,并捕获约束冲突,返回明确的操作结果:

CREATE OR REPLACE FUNCTION book_workstation(p_booked_date DATE, p_seat_id INT, p_employee_id INT)
RETURNS TEXT AS $$
BEGIN
  -- 执行原子插入
  INSERT INTO workstation_booking (booked_date, seat_id, employee_id)
  VALUES (p_booked_date, p_seat_id, p_employee_id);
  
  RETURN '预订成功';
EXCEPTION
  WHEN unique_violation THEN
    -- 根据触发的约束返回具体错误信息
    IF SQLERRM LIKE '%uq_employee_day%' THEN
      RETURN '错误:您今日已预订过工位';
    ELSIF SQLERRM LIKE '%uq_seat_day%' THEN
      RETURN '错误:该工位今日已被其他员工预订';
    ELSE
      RETURN '错误:预订失败,存在重复记录';
    END IF;
END;
$$ LANGUAGE plpgsql;

3. 调用函数完成预订

应用层直接调用该函数即可完成预订,无需自行处理查询与插入的并发问题:

-- 示例:预订2024-05-20日的101号工位给员工5001
SELECT book_workstation('2024-05-20', 101, 5001);

方案优势

  • 原子性:插入操作单事务原子执行,彻底规避先查后插的竞态漏洞。
  • 约束兜底:即使函数逻辑出现异常,数据库约束仍能阻止违规数据写入。
  • 清晰反馈:函数返回明确的结果或错误信息,方便应用层直接对接用户展示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 03:55:15