Имеются две базы. Я провожу синхронизацию данных, и на это время мне надо заблокировать таблицы,
чтобы пользователь не получил неверные данные и не нарушил процедуру.
Написал такую функцию:
------------------------------------------------- --функция для проведения репликации одной таблицы ------------------------------------------------- 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
http://postgresql.ru.net/manual/sql-lock.html
Я тут уже
Я тут уже смотрел, но когда я делаю:
он ругается на 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.
Таким транзакционным блоком в данном случае является тело функции.
ок, спасибо!
ок, спасибо!
хммм..а никто не
хммм..а никто не знает как на удаленную БД наложить блок?
т.е. мне надо подключиться к БД, заблокировать там таблицу, выполнить операции с ней и разблокировать.
как ето можно сделать?
т.е. я тут подключаесь к УБД, блокирую локальную и удаленную таблицы, и в цикле надо вставить данные.
Без блока 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. Иначе о каком транзакционном блоке может идти речь, если у нас будет для каждой команды свой коннект?