помогите наложить блокировку на таблицу

Имеются две базы. Я провожу синхронизацию данных, и на это время мне надо заблокировать таблицы,
чтобы пользователь не получил неверные данные и не нарушил процедуру.
Написал такую функцию:

-------------------------------------------------
--функция для проведения репликации одной таблицы
-------------------------------------------------
CREATE OR REPLACE FUNCTION table_insr() 
returns integer AS
$body$
declare 
	count integer <img class="ccfilter smileys" src="https://pgdocs.ru/sites/all/modules/ccfilter/smileys/ai.gif" alt="=0" title="=0" />;
	myrec record;
begin
	--коннект к базе
	perform dblink_connect('host=127.0.0.1 dbname=slave user=postgres password=zzcz2com');
              --тут надо наложить блок на таблицу tab_slave и tab_1
	--синхронизирую вставки
	FOR myrec IN SELECT * FROM inserted LOOP
 
	IF ((SELECT * FROM dblink('host=127.0.0.1 dbname=slave user=postgres password=zzcz2com',
	'select tm from time_rep limit 1') AS t (time timestamp without time zone)) < myrec.time) 
	then
 
	perform dblink_exec('insert into tab_slave select * from dblink('|| chr(39) ||'host=127.0.0.1 dbname=test user=postgres password=zzcz2com'||
	chr(39)|| ',' || chr(39) || 'select * from tab_1 where id =' || myrec.id || chr(39) ||') as t (id integer, name varchar(20))');
 
	count = count+1;
	end IF;
	end loop;
 
	--синхронизирую удаления
	FOR myrec IN SELECT * FROM deleted LOOP
 
	IF ((SELECT * FROM dblink('host=127.0.0.1 dbname=slave user=postgres password=zzcz2com',
	'select tm from time_rep limit 1') AS t (time timestamp without time zone)) < myrec.time) 
	then
 
	perform dblink_exec('delete from tab_slave where id =' || myrec.id);
 
	count = count+1;
	end IF;
	end loop;
 
	--синхронизирую
	FOR myrec IN SELECT * FROM updated LOOP
 
	IF ((SELECT * FROM dblink('host=127.0.0.1 dbname=slave user=postgres password=zzcz2com',
	'select tm from time_rep limit 1') AS t (time timestamp without time zone)) < myrec.time) 
	then
 
	perform dblink_exec('delete from tab_slave where id =' || myrec.id);
 
	perform dblink_exec('insert into tab_slave select * from dblink('|| chr(39) ||'host=127.0.0.1 dbname=test user=postgres password=zzcz2com'||
	chr(39)|| ',' || chr(39) || 'select * from tab_1 where id =' || myrec.id || chr(39) ||') as t (id integer, name varchar(20))');
 
	count = count+1;
	end IF;
	end loop;
 
	--обновляем время проведенной синхронизации в удаленной бд
	perform dblink_exec('update time_rep set tm=' || quote_literal((now()))); 
 
             --снять блокировки
	--диссконект
	perform dblink_disconnect();
	RETURN count;
end;
$body$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;
ALTER FUNCTION table_insr() OWNER TO postgres;

Подскажите как это сделать, что то никак не могу понять, буду очень благодарен!

Опции просмотра комментариев

Выберите предпочитаемый вами способ показа комментариев и нажмите "Сохранить настройки" для активации изменений.

http://postgresql.ru.net/manu

Я тут уже

Я тут уже смотрел, но когда я делаю:

CREATE OR REPLACE FUNCTION table_insr() 
returns integer AS
$body$
declare 
	count integer <img class="ccfilter smileys" src="https://pgdocs.ru/sites/all/modules/ccfilter/smileys/ai.gif" alt="=0" title="=0" />;
	myrec record;
begin
          begin work;
           LOCK tab_1;
          .........................
          commit work;
end;
$body$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;
ALTER FUNCTION table_insr() OWNER TO postgres;

он ругается на begin work и ничего не работает =(

А какой смысл

А какой смысл лочить таблицу во время транзакции?
Ведь до окончания транзакции никакие другие программы результатов выполнения транзакции не увидят.
Лочить надо ДО и снимать блокировку ПОСЛЕ. Причём смысл имеет только если между ДО и ПОСЛЕ несколько транзакций или действий, иначе всё что нужно даёт сама транзакция.

Функция

Функция синхронизирует таблицы из разных БД.
И дело в том, что если пользователь в удаленной БД во время выполнения будет
читать или писать в таблицу, то результаты будут неверны. Чтобы избежать этого я и хочу залочить
таблицы.
В моем случае как раз между ДО и ПОСЛЕ выполняются несколько процедур:
вставка, удаление и изменение таблицы.

Вот и делайте

Вот и делайте лок ДО, снимая его в конце.

я в третьем

я в третьем посте написал, что pg не пропускает блок "begin work - commit work".

Или залочить можно как то еще?

а зачем begin work - commit work?

А без begin work - commit work не пробовали?
Просто LOCK ...

Lock это

Lock это заблокировать..
а разлочить потом как, или она автоматически снимается?

begin ... commit - транзакция

LOCK TABLE is useless outside a transaction block: the lock would remain held only to the completion of the statement. Therefore PostgreSQL reports an error if LOCK is used outside a transaction block. Use BEGIN and COMMIT (or ROLLBACK) to define a transaction block.

Таким транзакционным блоком в данном случае является тело функции.

ок, спасибо!

ок, спасибо!

хммм..а никто не

хммм..а никто не знает как на удаленную БД наложить блок?
т.е. мне надо подключиться к БД, заблокировать там таблицу, выполнить операции с ней и разблокировать.
как ето можно сделать?

        erform dblink_connect('host=127.0.0.1 dbname=slave user=postgres password=zzcz2com');
 
        LOCK tab_1;
        perform dblink_exec('lock tab_slave');
        n = (SELECT count(*) FROM inserted);
	IF (n!=0) then
	--для всех записей в таблице inserted
	FOR myrec IN SELECT * FROM inserted LOOP
 
	--если время реплики меньше времени вставки
	IF ((SELECT * FROM dblink('host=127.0.0.1 dbname=slave user=postgres password=zzcz2com',
	'select tm from time_rep limit 1') AS t (time timestamp without time zone)) < myrec.time) 
	then
 
	--в таблицы клиента вставляем строки, которые были изменены, т.е. проверяем таблицу inserted, если время вставки
	--в таблицу позже временя последней синхронизации, то ищем строку в таблицу tab_1 по идентификатору, укаанному в
	--таблице inserted
 
	perform dblink_exec('insert into tab_slave select * from dblink('|| chr(39) ||'host=127.0.0.1 dbname=test user=postgres password=zzcz2com'||
	chr(39)|| ',' || chr(39) || 'select * from tab_1 where id =' || myrec.id || chr(39) ||') as t (id integer, name varchar(20))');	
 
	cc = cc+1;
	end IF;
	end loop;
	end IF;

т.е. я тут подключаесь к УБД, блокирую локальную и удаленную таблицы, и в цикле надо вставить данные.
Без блока tab_slave операции проходят успешно, как только блокирую все виснет...

а вот здесь нужен begin ... commit

Попробуйте (по крайней мере - логично):
perform dblink_exec('begin work');
perform dblink_exec('lock tab_slave');
........
perform dblink_exec('commit work');

не помогло, все

не помогло, все равно виснет все, приходится даже сервис перезапускать...

может следует навести порядок с dblink

Возможно, стоит привести действия к такой схеме:
1. Сделать именованный коннект.
2. Выполнить последовательность комманд (begin, lock, ..., ..., ... , commit), обращаясь к имени коннекта.
3. Сделать дисконнект.
Ну и, конечно же, не выполнять весь задуманный функционал сразу, а начать с минимума элементарных действий, дабы не запутаться. А когда получиться, то наращивать функционал.

например, че та

например, че та не понял, именованый конект это как?

наверное, неправильно выразился

dblink_connect(text connname, text connstr) returns text
где conname -
The name to use for this connection; if omitted, an unnamed connection is opened, replacing any existing unnamed connection
Напрмер:
dblink_connect('myconn', 'dbname=postgres');
Затем работать с ним:
dblink_exec(text connname, text sql [, bool fail_on_error]) returns text
When two text arguments are given, the first one is first looked up as a persistent connection's name; if found, the command is executed on that connection. If not found, the first argument is treated as a connection info string as for dblink_connect, and the indicated connection is made just for the duration of this command.
Например:
dblink_exec('myconn', 'insert into foo values(21,''z'',''{"a0","b0","c0"}'');');
Т.е., если я правильно понимаю, в этом случае мы можем быть уверены, что работаем с одним и тем же коннектом, и можно говорить уже о транзакции, в пределах которой как уже выяснили и работает LOCK. Иначе о каком транзакционном блоке может идти речь, если у нас будет для каждой команды свой коннект?

Опции просмотра комментариев

Выберите предпочитаемый вами способ показа комментариев и нажмите "Сохранить настройки" для активации изменений.

Back to top

(С) Виктор Вислобоков, 2008-2023