YCF*_*F_L 5 sql postgresql plpgsql
我正在尝试在函数内创建一个事务块,所以我的目标是一次使用这个函数,所以如果有人使用这个函数而另一个人想使用它,他不能直到第一个完成我创建了这个函数:
CREATE OR REPLACE FUNCTION my_job(time_to_wait integer) RETURNS INTEGER AS $$
DECLARE
max INT;
BEGIN
BEGIN;
SELECT MAX(max_value) INTO max FROM sch_lock.table_concurente;
INSERT INTO sch_lock.table_concurente(max_value, date_insertion) VALUES(max + 1, now());
-- Sleep a wail
PERFORM pg_sleep(time_to_wait);
RETURN max;
COMMIT;
END;
$$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
但它接缝不起作用,我有一个错误语法错误 BEGIN;
没有BEGIN;
并且COMMIT
我得到了正确的结果,我使用这个查询来检查:
-- First user should to wait 10 second
SELECT my_job(10) as max_value;
-- First user should to wait 3 second
SELECT my_job(3) as max_value;
Run Code Online (Sandbox Code Playgroud)
所以结果是:
+-----+----------------------------+------------+
| id | date | max_value |
+-----+----------------------------+------------+
| 1 | 2017-02-13 13:03:58.12+00 | 1 |
+-----|----------------------------+------------+
| 2 | 2017-02-13 13:10:00.291+00 | 2 |
+-----+----------------------------+------------+
| 3 | 2017-02-13 13:10:00.291+00 | 2 |
+-----+----------------------------+------------+
Run Code Online (Sandbox Code Playgroud)
但结果应该是:
+-----+----------------------------+------------+
| id | date | max_value |
+-----+----------------------------+------------+
| 1 | 2017-02-13 13:03:58.12+00 | 1 |
+-----|----------------------------+------------+
| 2 | 2017-02-13 13:10:00.291+00 | 2 |
+-----+----------------------------+------------+
| 3 | 2017-02-13 13:10:00.291+00 | 3 |
+-----+----------------------------+------------+
Run Code Online (Sandbox Code Playgroud)
所以第三个id = 3
应该有max_value = 3
and not 2
,这是因为第一个用户选择 max = 1 并等待10 sec
,第二个用户选择 max = 1 并3 sec
在插入前等待,但正确的解决方案是:我不能使用这个函数直到第一个完成,为此我想制作一些安全和受保护的东西。
我的问题是:
谢谢你。
好吧,所以你不能COMMIT
在函数中。但是,您可以拥有一个保存点并回滚到该保存点。
最小的可能事务是服务器从客户端解析和执行的单个语句,因此每个事务都是一个函数。然而,在一次交易中,您可以拥有保存点。在这种情况下,您将查看 PostgreSQL 的异常处理部分来处理此问题。
但这不是您想要的。您希望(我认为?)数据在长时间运行的服务器端操作期间可见。为此,你有点不走运。在运行函数时,您无法真正增加事务 ID。
您有几个选择,按照我认为的良好实践的顺序(最好到最差):