如何在函数中使用 SELECT...FOR UPDATE?
How do you use SELECT...FOR UPDATE in a function?
离开this example,我正在尝试锁定某人的信用卡帐户(行),检查他们是否有足够的钱,如果有,就用它来支付。我需要锁定它以防止他们有足够信用的情况,但随后它被用于另一笔交易,我的程序仍然认为它仍然有足够的信用。
在终端级别,我可以这样完成:我可以在两个终端中打开两个 psql
会话,我可以在一个终端中发出 SELECT * FROM credit_card WHERE credit_card_number = 1234 FOR UPDATE;
命令,然后发出 SELECT * FROM credit_card FOR UDPATE
在另一个(或其他类似 UPDATE credit_card SET credits = credits -99 WHERE credit_card_number = 1234
)中,我可以看到前一个调用阻止了后一个调用。但是,当我做同样的事情但在这样的函数中时
CREATE OR REPLACE FUNCTION foo (p_credit_card_number BIGINT)
RETURNS VOID
AS $$
BEGIN
SELECT * FROM credit_card WHERE credit_card_number = p_credit_card_number FOR UPDATE
...
END
$$
LANGUAGE 'plpgsql';
我得到了典型的 query has no destination for result data
错误(例如,参见 here)。
问题: 如何在函数内部使用 SELECT ...FOR UPDATE
时锁定特定行或行数,同时避免上述错误?如果不可能或不可取,我还能如何在函数内执行此操作?
您遇到的错误与“for update”子句无关。它在 not 的存储过程中工作完全相同。您必须在过程(或函数或 do 块)内执行 select 语句的错误。当您在过程中 select 时,您 必须 告诉过程如何处理 selected 变量。
你用 Select 做成 ...
因此,假设您确实需要数据,那么如下所示:
create or replace function foo (p_credit_card_number bigint)
returns void
language 'plpgsql'
as $$
v_credit_card credit_card%type;
begin
select *
into v_credit_card
from credit_card
where credit_card_number = p_credit_card_number
for update;
...
update credit_card
set ...
where credit_card = v_credit_card ;
end;
$$;
虽然更常见的用法是使用 'where current of'
创建游标和更新
create or replace function foo (p_credit_card_number bigint)
returns void
language 'plpgsql'
as $$
c_credit_cards cursor for
select *
from credit_card
where credit_card_number = p_credit_card_number
for update;
v_credit_card credit_card%type;
begin
for v_cc in c_credit_cards
loop
... additional processing ...
update credit_card
set ...
where current of c_credit_cards;
end loop;
...
end;
但请注意,当游标打开时,其中的所有行都被锁定。
离开this example,我正在尝试锁定某人的信用卡帐户(行),检查他们是否有足够的钱,如果有,就用它来支付。我需要锁定它以防止他们有足够信用的情况,但随后它被用于另一笔交易,我的程序仍然认为它仍然有足够的信用。
在终端级别,我可以这样完成:我可以在两个终端中打开两个 psql
会话,我可以在一个终端中发出 SELECT * FROM credit_card WHERE credit_card_number = 1234 FOR UPDATE;
命令,然后发出 SELECT * FROM credit_card FOR UDPATE
在另一个(或其他类似 UPDATE credit_card SET credits = credits -99 WHERE credit_card_number = 1234
)中,我可以看到前一个调用阻止了后一个调用。但是,当我做同样的事情但在这样的函数中时
CREATE OR REPLACE FUNCTION foo (p_credit_card_number BIGINT)
RETURNS VOID
AS $$
BEGIN
SELECT * FROM credit_card WHERE credit_card_number = p_credit_card_number FOR UPDATE
...
END
$$
LANGUAGE 'plpgsql';
我得到了典型的 query has no destination for result data
错误(例如,参见 here)。
问题: 如何在函数内部使用 SELECT ...FOR UPDATE
时锁定特定行或行数,同时避免上述错误?如果不可能或不可取,我还能如何在函数内执行此操作?
您遇到的错误与“for update”子句无关。它在 not 的存储过程中工作完全相同。您必须在过程(或函数或 do 块)内执行 select 语句的错误。当您在过程中 select 时,您 必须 告诉过程如何处理 selected 变量。
你用 Select
因此,假设您确实需要数据,那么如下所示:
create or replace function foo (p_credit_card_number bigint)
returns void
language 'plpgsql'
as $$
v_credit_card credit_card%type;
begin
select *
into v_credit_card
from credit_card
where credit_card_number = p_credit_card_number
for update;
...
update credit_card
set ...
where credit_card = v_credit_card ;
end;
$$;
虽然更常见的用法是使用 'where current of'
创建游标和更新create or replace function foo (p_credit_card_number bigint)
returns void
language 'plpgsql'
as $$
c_credit_cards cursor for
select *
from credit_card
where credit_card_number = p_credit_card_number
for update;
v_credit_card credit_card%type;
begin
for v_cc in c_credit_cards
loop
... additional processing ...
update credit_card
set ...
where current of c_credit_cards;
end loop;
...
end;
但请注意,当游标打开时,其中的所有行都被锁定。