如何为PostgreSQL编写自己的全局锁定/解锁函数

时间:2010-04-13 20:35:32

标签: sql postgresql concurrency locking blocking

我有postgresql(在perlu中)函数getTravelTime(整数,时间戳),它试图选择指定ID和时间戳的数据。如果没有数据或者数据是旧的,则从外部服务器下载它们(下载时间约为300毫秒)。

多个进程使用此数据库和此功能。当两个进程找不到数据并下载它们并尝试插入travel_time表时,会出现错误(id和timestamp对必须是唯一的)。我想到了锁。锁定整个表将阻止所有进程并且只允许一个进程。我只需要锁定id和时间戳。 pg_advisory_lock似乎只锁定在“当前会话”中。但我的流程使用自己的会话。

我试着编写自己的锁定/解锁功能。我做得对吗?我使用主动等待,我怎么能省略这个?也许有一种方法可以使用pg_advisory_lock()作为全局锁?

我的代码:

CREATE TABLE travel_time_locks (
    id_key integer NOT NULL,
    time_key timestamp without time zone NOT NULL,
    UNIQUE (id_key, time_key) 
);

------------
-- Function: mylock(integer, timestamp)
DROP FUNCTION IF EXISTS mylock(integer, timestamp) CASCADE;
-- Usage: SELECT mylock(1, '2010-03-28T19:45');
-- function tries to do a global lock similar to pg_advisory_lock(key, key)
CREATE OR REPLACE FUNCTION mylock(id_input integer, time_input timestamp)
  RETURNS void AS
$BODY$
DECLARE
    rows int;
BEGIN
    LOOP

        BEGIN
            -- active waiting here !!!! :(
            INSERT INTO travel_time_locks (id_key, time_key) VALUES (id_input, time_input);
        EXCEPTION WHEN unique_violation THEN
            CONTINUE;
        END;
        EXIT;
    END LOOP;
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE
    COST 1;

------------
-- Function: myunlock(integer, timestamp)
DROP FUNCTION IF EXISTS myunlock(integer, timestamp) CASCADE;
-- Usage: SELECT myunlock(1, '2010-03-28T19:45');
-- function tries to do a global unlock similar to pg_advisory_unlock(key, key)
CREATE OR REPLACE FUNCTION myunlock(id_input integer, time_input timestamp)
  RETURNS integer AS
$BODY$
DECLARE
BEGIN
    DELETE FROM ONLY travel_time_locks WHERE id_key=id_input AND time_key=time_input;
    RETURN 1;
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE
    COST 1;

2 个答案:

答案 0 :(得分:5)

使用pg_advisory_lock()。这正是你所需要的。

答案 1 :(得分:1)

经过进一步测试后,我发现“当前会话”意味着PostgreSQL后端的整个实例,而不仅仅是一个连接。

我的解决方案是PERFORM pg_advisory_lock(id, extract(epoch from my_time)::int );(+解锁)在我的getTravelTime函数中。