postgresql - Postgres函数/存储过程中的条件锁定
问题描述
我正在为网络爬虫构建事件溯源服务,其中有几个爬虫工作人员抓取多个网站并试图为爬取的资源保留增量。我选择 PostgreSQL 作为底层数据存储。我需要让生产者能够使用名为“expectedSeq”的标志进行乐观锁定,以控制是否应为特定流写入事件。最初,我使用的是一个表,利用事务的自动增量为每个“流”构建乐观锁定功能,但我很快发现服务器可以处理多少个表存在文件系统上限。
由于我不能再使用自动增量,我试图使用两个表来构建这个功能,一个用于控制流的顺序,另一个用于存储事件本身。
我的第一个问题是,我应该使用存储过程还是函数。第二个是可以在存储过程或 Postgres 函数中包含条件事务。
我需要实现的逻辑有点像
storeEvent(stream, expectedSeq = null)
lock row for `streams`.stream
if expectedSeq = null
update stream row with seq + 1
release lock
write event to event table
else
if expectedSeq != seq + 1
release lock
abort
else
update seq + 1
release lock
write event to event table
解决方案
感谢伊恩哈里斯
CREATE OR REPLACE PROCEDURE store_event (v_topic varchar(40), v_expected_next_seq integer, v_data text)
LANGUAGE plpgsql
AS $$
DECLARE
next_seq integer;
BEGIN
-- FOR UPDATE clause places row level lock on table
next_seq := (
SELECT
seq
FROM
topics
WHERE
topic = v_topic
FOR UPDATE) + 1;
IF v_expected_next_seq IS NOT NULL AND next_seq != v_expected_next_seq THEN
RAISE 'Optimistic locking error';
END IF;
IF next_seq IS NULL THEN
RAISE 'Unknown topic';
END IF;
UPDATE
topics
SET
seq = next_seq
WHERE
topic = v_topic;
INSERT INTO events (topic, seq, data)
VALUES (v_topic, next_seq, v_data);
COMMIT;
END;
$$;
推荐阅读
- qt - QPainter::drawText() 的第一次调用需要很长时间导致闪烁
- python - 对 Callable 的 mypy 类型检查认为成员变量是一种方法
- css - 如何在 SenseDateRangePicker 扩展中更改用户输入的 CSS 字体
- javascript - 为什么我不能调用存储在数组中的 jQuery 方法?
- flutter - Flutter Textwrapping 在堆叠的列和行中
- java - 你如何让 ActionListener 根据 actionPerformed 执行不同的事件?
- laravel - 网址中的位置代码 - Laravel
- javascript - 使用 Vue.js 更改 DOM 元素的值
- ios - iOS swift中具有多个和单个选择的下拉表视图?
- sql - 加入两个表不断返回无效数字 ORA-01722