Postgres在函数内部锁定表不起作用?

时间:2018-09-05 06:53:05

标签: postgresql

CREATE OR REPLACE FUNCTION() 
RETURND VOID AS

BEGIN

FOR I IN 1..5
LOOP
LOCK TABLE tbl_Employee1 IN EXCLUSIVE MODE;
INSERT INTO tbl_Employee1
VALUES 
(i,'test');

END LOOP;

COMMIT;

END;
$$ LANGUAGE PLPGSQL

当我选择表格时,它将进入无限循环,这表示事务未完成。请帮帮我吗?

1 个答案:

答案 0 :(得分:1)

您的代码已被精简,以至于不再有意义。

但是,您应该只锁定一次表,而不是在循环的每次迭代中。另外,您不能在Postgres的函数中使用commit,因此也必须将其删除。不提供insert语句的列名也是不好的编码风格(在Postgres Oracle中)。

立即解决方案:

CREATE OR REPLACE FUNCTION ...
  RETURNS VOID AS
$$
BEGIN
  LOCK TABLE Employee1 IN EXCLUSIVE MODE;
  FOR I IN 1..5 LOOP
    INSERT INTO Employee1 (id, name)
    VALUES (i,'test');
  END LOOP;
  -- no commit here!    
END;
$$ LANGUAGE PLPGSQL

以上内容在Postgres中不必要地复杂,可以更有效地实现很多,而无需循环:

CREATE OR REPLACE FUNCTION ....
  RETURNS VOID AS
$$
BEGIN
  LOCK TABLE Employee1 IN EXCLUSIVE MODE;
  INSERT INTO Employee1 (id, name)
  select i, test
  from generate_series(1,5);

END;
$$ LANGUAGE PLPGSQL

首先以互斥模式锁定表似乎是个坏主意。在Oracle中也是如此,但在Postgres中可能有更多severe implications。如果要防止表中出现重复项,请创建唯一索引(或约束)并处理错误。或在Postgres中使用insert ... on conflict。这将比锁定整个表更加有效(和可扩展)。

此外:LOCK TABLE IN EXCLUSIVE MODE;在Oracle和Postgres中表现不同。尽管Oracle仍然允许对该表进行只读查询,但是您可以在Postgres中阻止对其的每次访问-包括 SELECT语句。