заблокировать строки до следующего выбора postgres - PullRequest
2 голосов
/ 01 января 2011

Есть ли в postgres способ заблокировать строки до следующего выполнения запроса select из той же системы. И еще одна вещь - , процесс блокировки заблокированных строк не будет. сценарий что-то вроде этого

Если таблица1 содержит данные типа

id |    txt
-------------------
1 |    World 
2 |    Text
3 |    Crawler
4 |    Solution
5 |    Nation
6 |    Under
7 |    Padding
8 |    Settle
9 |    Begin
10 |    Large
11 |    Someone
12 |    Dance

Если sys1 выполняется

select * from table1 order by id limit 5;

тогда он должен заблокировать строку с идентификатором 1 до 5 для другой системы, которая одновременно выполняет оператор выбора.

Позже, если sys1 снова выполнит другой запрос на выборку, например

select * from table1 where id>10 order by id limit 5;

тогда заблокированные строки должны быть освобождены.

Ответы [ 3 ]

4 голосов
/ 01 января 2011

Я не думаю, что это возможно.Вы не можете заблокировать доступ к таблице только для чтения (если только выбор не сделан FOR UPDATE)

Насколько я могу судить, единственный шанс, который у вас есть, - использовать функцию pg_advisory_lock().http://www.postgresql.org/docs/current/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS

Но для этого требуется «ручное» снятие замков, полученных через него.Вы не получите автоматическую разблокировку с этим.

Для блокировки строк вам понадобится что-то вроде этого:

select pg_advisory_lock(id), * 
from 
( 
  select * table1 order by id limit 5
) t

(Обратите внимание на использование производной таблицы для части LIMIT.См. Ссылку на руководство, которую я разместил для объяснения)

Затем вам нужно сохранить полученные идентификаторы, а затем позвонить pg_advisory_unlock() для каждого идентификатора.

Если каждый процесс всегда выпускает все идентификаторы одновременно, вы можете просто использовать pg_advisory_unlock_all() вместо этого.Тогда вам не нужно будет сохранять полученные идентификаторы.

Обратите внимание, что это не не позволит другим читать строки, используя «обычные» операции выбора.Это будет работать, только если каждый процесс, который обращается к этой таблице, использует один и тот же шаблон получения блокировок.

0 голосов
/ 02 января 2011

Я попробовал оба выбрать ... для обновления и pg_try_advisory_lock и мне удалось приблизиться к моему требованию.

/*rows are locking but limit is the problem*/
select * from table1 where  pg_try_advisory_lock( id) limit 5;
.
.
$_SESSION['rows'] = $rowcount; // no of row to process
.
.
/*afer each process of word*/
$_SESSION['rows'] -=1;
.
.
/*and finally unlock locked rows*/
if ($_SESSION['rows']===0)
select pg_advisory_unlock_all() from table1

Но есть две проблемы
1. Поскольку Limit будет применяться до блокировки, каждый раз, когда одни и те же строки пытаются заблокировать в другом экземпляре.
2. Не уверен, разблокирует ли pg_advisory_unlock_all строки, заблокированные текущим экземпляром или всем экземпляром.

0 голосов
/ 01 января 2011

Похоже, у вас действительно есть транзакция, которая выходит за границы вашей базы данных, и все изменения происходят в другой системе.

Моя идея select ... for update no wait заблокировать соответствующие строки, а затем разгрузитьданные в другую систему, затем rollback, чтобы разблокировать строки.Ни один из двух select ... for update запросов не выберет одну и ту же строку, а второй select сразу завершится неудачей, вместо того, чтобы ждать и продолжить.

Но вы, похоже, не помечаете выгруженные записи в любом случае;Я не понимаю, почему два непоследовательных выбора не будут удачно выбирать перекрывающийся диапазон.Таким образом, я все еще update записей с флагом и / или именем целевого пользователя и выбрал бы только записи с не установленным флагом.

...