Given(PostgreSQL 15.3):
create table test (
test_id int2,
test_val int4,
primary key (test_id)
);
字符串
如果这两个事务在read committed
隔离级别并行运行:
-- Transaction 1
insert into test (select 1, 1 from pg_sleep(2));
-- Transaction 2
select coalesce(
(select test_val from test where test_id = 1),
(select null::int4 from pg_sleep(5)),
(select test_val from test where test_id = 1)
);
的数据
第二个事务返回null
,因为它是一个单独的语句。
但是,如果第二个事务替换为:
create function select_testval
(id int2) returns int4
language sql strict volatile -- stable function will work as previous version
return (select test_val from test where test_id = id);
-- Transaction 2.1
select coalesce(
(select test_val from test where test_id = 1),
(select null::int4 from pg_sleep(5)),
select_testval(1::int2)
);
型
它返回1
,作为一系列两个语句,每个语句看到不同的数据快照。
我的问题是
1.函数调用引入一个单独的语句来查看一个较新的快照,这是一个正确的行为吗?如果是,在哪里记录?
1.显然,在这种情况下,stable
函数被内联,因此仍然是一条语句。在某些情况下,volatile
函数调用是否也可以内联,从而改变并发语义?如果是,如何控制内联?
编辑1.根据评论的反馈,编辑了帖子,以找出造成混乱的实际问题。最初的问题相当琐碎。
P.S.对于上下文,我在试图找到一个惯用的纯SQL解决方案来解决具有唯一约束问题(1,2)的并发插入时发现了这一点,而不是求助于plpgsql
。
1条答案
按热度按时间67up9zun1#
好吧,看来我真的忽略了标准文档:
STABLE
和IMMUTABLE
函数使用在调用查询开始时建立的快照,而VOLATILE
函数在它们执行的每个查询开始时获取新的快照。从38.7. Function Volatility Categories
此行为与内联无关。
值得注意的是,
volatile
函数获得的快照符合事务隔离级别。因此,当隔离度为repeatable read
时,该函数不会看到来自其他事务的任何新数据。