我正在寻求澄清如何在plpgsql函数中确保原子事务,以及为数据库的这一特定更改设置隔离级别。
在下面显示的plpgsql函数中,我想确保删除和插入成功。当我尝试将它们包装在单个事务中时,我收到错误:
ERROR: cannot begin/end transactions in PL/pgSQL
。
如果其他用户在此函数删除了自定义行之后添加了环境的默认行为('RAIN','NIGHT','45MPH'),则在执行下面的函数时会发生什么? 之前它有机会插入自定义行吗?是否存在包含插入和删除的隐式事务,以便在另一个用户更改此函数引用的任一行时回滚它们?我可以为此功能设置隔离级别吗?
create function foo(v_weather varchar(10), v_timeofday varchar(10), v_speed varchar(10),
v_behavior varchar(10))
returns setof CUSTOMBEHAVIOR
as $body$
begin
-- run-time error if either of these lines is un-commented
-- start transaction ISOLATION LEVEL READ COMMITTED;
-- or, alternatively, set transaction ISOLATION LEVEL READ COMMITTED;
delete from CUSTOMBEHAVIOR
where weather = 'RAIN' and timeofday = 'NIGHT' and speed= '45MPH' ;
-- if there is no default behavior insert a custom behavior
if not exists
(select id from DEFAULTBEHAVIOR where a = 'RAIN' and b = 'NIGHT' and c= '45MPH') then
insert into CUSTOMBEHAVIOR
(weather, timeofday, speed, behavior)
values
(v_weather, v_timeofday, v_speed, v_behavior);
end if;
return QUERY
select * from CUSTOMBEHAVIOR where ... ;
-- commit;
end
$body$ LANGUAGE plpgsql;
答案 0 :(得分:39)
plpgsql函数自动在事务中运行。一切都成功或者都失败了。 The manual:
函数和触发程序总是在a中执行 由外部查询建立的事务 - 它们无法启动或 提交该事务,因为它们没有上下文 执行。但是,包含
EXCEPTION
子句的块 有效地形成一个可以无需回滚的子事务 影响外部交易。有关详情,请参阅Section 42.6.6.
所以,如果你需要,你可以捕获理论上可能发生的异常(但不太可能) Details on trapping errors in the manual.
您的功能已经过审核和简化:
CREATE FUNCTION foo(v_weather text
, v_timeofday text
, v_speed text
, v_behavior text)
RETURNS SETOF custombehavior AS
$func$
BEGIN
DELETE FROM custombehavior
WHERE weather = 'RAIN'
AND timeofday = 'NIGHT'
AND speed = '45MPH';
INSERT INTO custombehavior (weather, timeofday, speed, behavior)
SELECT v_weather, v_timeofday, v_speed, v_behavior
WHERE NOT EXISTS (
SELECT FROM defaultbehavior
WHERE a = 'RAIN'
AND b = 'NIGHT'
AND c = '45MPH'
);
RETURN QUERY
SELECT * FROM custombehavior WHERE ... ;
END
$func$ LANGUAGE plpgsql;
如果您确实需要 开始/结束交易 ,如标题中所示,请查看Postgres 11或更高版本(CREATE PROCEDURE
)中的SQL过程。相关:
答案 1 :(得分:0)
START TRANSACTION;
select foo() ;
COMMIT;
"不幸的是Postgres没有存储过程,所以你总是需要在调用代码中管理事务" - a_horse_with_no_name