postgresql - 创建用户帐户竞争条件
问题描述
我有以下程序:
CREATE OR REPLACE FUNCTION create_user(p_email character varying) RETURNS integer AS
$$
DECLARE
v_user_id integer;
BEGIN
SELECT user_id FROM user WHERE email = p_email INTO v_user_id;
IF v_user_id IS NULL THEN
INSERT
INTO user (email, status)
VALUES (p_email, 'active')
RETURNING user_id INTO v_user_id;
END IF;
RETURN v_user_id;
END;
$$ LANGUAGE plpgsql;
但是,如果对 DB 有多个并行请求,则会导致竞争条件,该过程会被多次调用,并且由于延迟非常低,所有这些请求都试图创建一个用户,并且只有一个成功。有什么好的解决方法吗?
解决方案
有什么好的解决方法吗?
是的,在电子邮件列上创建一个唯一索引,然后使用insert on conflict
:
...
BEGIN
INSERT INTO "user" (email, status)
VALUES (p_email, 'active')
ON CONFLICT (email) DO NOTHING
RETURNING user_id INTO v_user_id;
RETURN v_user_id;
END;
但是,如果电子邮件已存在,则上述内容不会返回 user_id。如果你需要它,你将需要这样的东西:
...
BEGIN
INSERT INTO "user" (email, status)
VALUES (p_email, 'active')
ON CONFLICT (email) DO NOTHING
RETURNING user_id INTO v_user_id;
if v_user_id is null then
-- no insert happened
select user_id
into v_user_id
from "user"
where email = p_email;
end if;
RETURN v_user_id;
END;
推荐阅读
- java - HashMap中Bucket和Node的区别
- python - keras ValueError 的问题:检查目标时出错:预期的 dense_3 具有形状 (1,) 但得到的数组具有形状 (4,)
- java - 如何在 JAVA 中以非常精确的时间发送 HTTP 请求
- google-apps-script - 为什么我从 Google Apps 脚本中的 UrlFetchApp 收到空响应?
- flutter - 未处理的异常:处理后使用了一个类。- 颤振
- python - 如何制作 discord.py 自定义前缀系统?
- swift - 防止 NSPopover 剪裁屏幕外 - Swift 5
- c++ - Makefile 不检查头文件中的更新
- vue-formulate - 有没有办法将点击事件绑定到模式中的按钮?
- c# - 如何通过索引从一个非常大的列表中有效地删除元素?