我有一个有趣的问题,我和我的同事现在有些困难。
我在PostgreSQL-8.3中有一个PL / pgSQL函数(抱歉那个旧版本,我无法改变它),它执行以下四项操作:
简化功能:
CREATE OR REPLACE FUNCTION add_entry(_user_name text, _visible_attr integer[])
RETURNS bigint AS
$BODY$
DECLARE
user_name text := '#' || $1;
user_id bigint;
BEGIN
-- get the ID from the sequence
SELECT nextval('my_sequence') INTO user_id;
-- insert the name (and some other data not shown here) 5x
FOR item IN 1..5
LOOP
INSERT INTO mytable
(id,index,username,visible)
VALUES (user_id,item,user_name,$2[item]);
END LOOP;
-- send notify that an insertion took place
notify my_notify;
RETURN user_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
所以,我的同事从他的应用程序中调用了这个函数。他获取返回的ID并在其应用程序中使用另一个线程(DB池)来调用一个函数,该函数将返回先前使用该ID插入的数据。但是,这不是第一次工作。只有第二个请求他才能选择数据。似乎INSERT在函数已经返回时没有完成?!
我们检查了多次,数据将正确地插入到表中,但不知何时它的可用速度与返回值(序列中的ID)一样快!为什么会这样?
更新:错误的假设
我进一步检查并将示例缩减为一个真正显示问题的简单查询:
select * from mytable where id = (select add_entry('MyTestUser'));
此查询不返回任何行。但是,如果我在两个单独的步骤中执行此操作,我可以选择使用add_entry函数插入的数据。 击>
我不知道我做错了什么,或者我如何加快插入......
答案 0 :(得分:1)
实际上,SELECT查询会在查询开始运行的那一刻看到数据库的快照
由于更新是在select
本身完成的,因此不会看到插入的行。
http://www.postgresql.org/docs/8.3/static/tutorial-transactions.html
更改功能以返回setof mytable
。它可以是普通的SQL。要更改返回类型,必须先删除该功能
drop function add_entry(text);
create or replace function add_entry (_user_name text, _visible_attr integer[])
returns setof mytable as $body$
notify my_notify;
with ins as (
insert into mytable (id, index, username, visible)
select user_id, item, '#' || $1, $2[item]
from
generate_series(1, 5) g(item)
cross join
(values (nextval('my_sequence'))) s(user_id)
returning *
)
select * from ins;
$body$ language sql volatile;
通知必须在从函数返回任何内容之前发生。这不是一个问题,好像插入失败了事务回滚包括通知。称之为
select * from add_entry('MyTestUser');
select不会看到修改后的表,而是返回mytable
行。
如果函数必须为plpgsql
,请使用return query
create or replace function add_entry (_user_name text, _visible_attr integer[])
returns setof mytable as $body$
begin
notify my_notify;
return query
insert into mytable (id, index, username, visible)
select user_id, item, '#' || $1, $2[item]
from
generate_series(1, 5) g(item)
cross join
(values (nextval('my_sequence'))) s(user_id)
returning *
;
end;
$body$ language plpgsql volatile;