2015-12-23 3 views
2

Я хотел бы реализовать следующий сценарий в PosgreSQL от Java:сделки в PostgreSql

  • Пользователь выбирает данные
  • пользователь запускает транзакции: вставки, обновления, удаления данных
  • Пользователь совершает транзакции

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

Я пытался использовать select for update или select for share, но он также блокирует данные для чтения. Я пытался использовать команду lock, но я не могу получить блокировку (ERROR: could not obtain lock on relation "fppo10") или другая транзакция блокируется при попытке совершить транзакцию, а не при обновлении данных.

Существует ли способ блокировки данных в момент начала транзакции, чтобы предотвратить любой другой вызов update, insert или delete заявление?

У меня есть этот сценарий, который успешно работает в течение нескольких лет в базе данных DB2. Теперь мне нужно, чтобы такое же приложение работало и для PostgreSql.

+0

С одной стороны, вы говорите, что хотите, чтобы данные были недоступны для других во время транзакции. С другой стороны, вам не нравится, что данные 'select for update' блокируют данные для чтения, что кажется мне явно« недоступным для других ». Никакая блокировка не позволит другим клиентам из * try * выполнить инструкцию обновления; некоторые виды заставят их ждать. Чего вы действительно хотите? –

+0

@Mike Sherrill'Cat Recall «Проблема в том, что я не знаю, если пользователь хочет обновить данные в момент вызова * select * statement. Это ясно после любого * обновления *. Но уже слишком поздно. – agad

+0

Вы * не можете * знать, что другие пользователи хотят делать. Читайте об уровнях изоляции транзакций PostgreSQL (http://www.postgresql.org/docs/current/static/transaction-iso.html). –

ответ

1

Наконец-то, я думаю, что получаю то, что вы собираетесь делать.
Это не проблема «транзакции» как таковая (и в зависимости от количества таблиц, с которыми нужно иметь дело, и требуемых заявлений, возможно, вам даже не понадобится), это проблема -приложения. У вас есть два общих способа борьбы с этим; оптимистичная и пессимистическая блокировка.

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

Оптимистичная блокировка считывает ряд (или набор), а не принимает любые блокировки уровня db. Это лучше всего использовать, если вы просто читаете строки, без какого-либо непосредственного плана по обновлению любого из них. Обычно данные в строке будут содержать значение «версия» (сгенерированный счетчик или последняя обновленная временная метка). Если ваше приложение переходит к обновлению строки, оно сравнивает исходное значение (ы) данных, чтобы убедиться, что оно не было изменено чем-то другим в первую очередь, и предупреждает пользователя, если данные были изменены. Большинство приложений, взаимодействующих с пользователями, должны использовать оптимистичную блокировку. Тем не менее, он требует, чтобы пользователи замечали и обращали внимание на обновленные значения.

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


Т.Л., др

Не заблокировать строки при чтении. Просто сравните старые значения с тем, что приложение прочитало в последний раз, и отклоните обновление, если они не совпадают (и предупреждают пользователя). Обучите своих пользователей соответствующим образом реагировать.

+0

Хотя это не тот ответ, который я искал, я отмечаю этот ответ как правильный , Я просто не могу поверить, что вещь, которая так красиво работает в DB2 без каких-либо усилий, не возможна в PostgreSql :-( – agad

+1

@agad - я уверен, что ваше приложение DB2 1) фактически не делает то, что вы ожидаете (по крайней мере, не полностью, см. мой первый комментарий к вашему вопросу) и 2] не действуя в интересах ваших пользователей (вероятность блокировки слишком велик). Кроме того, 'SELECT FOR UPDATE' не следует использовать для прокрутки строки - ваша текущая проблема заключается в том, что у вас есть два процесса, выполняющих это для одной и той же строки, что, конечно, конфликты. Но выполнение «SELECT» без блокировки сначала во время прокрутки снова возвращает вас обратно к этому ответу ... –

+0

Приложение работает в течение нескольких лет (и работает по-прежнему). На этот раз никто не жалуется. Пользователи довольны тем, что они видят фактические данные и знают, что кто-то обновляет их. Проблема связана с просьбой сделать приложение, работающее также с Postgre Текущее приложение привел к несогласованности db при попытке запустить против Postgre, потому что 2 пользователя обновили db в одно и то же время. – agad

1

Вместо select for update попробовать "строку эксклюзивный" блокировку таблицы:

LOCK TABLE YourTable IN ROW EXCLUSIVE MODE; 

Согласно documentation, этот замок:

команды UPDATE, DELETE и INSERT приобрести этот режим блокировки на целевую таблицу (в дополнение к блокировке ACCESS SHARE на любых других таблицах, привязанных к ). В общем, этот режим блокировки будет получен любой командой , которая изменяет данные в таблице.

Обратите внимание, что название замка сбивает с толку, но это заблокировать всю таблицу:

Помните, что все эти режимы блокировки являются блокировки таблицы уровня, даже если имя содержит слово «строка»; имена режимов блокировки: исторические

+0

Согласно документации, она выглядит нормально, но когда я это пробовал, исключение не было выбрано в момент обновления таблицы, но когда commit был вызван – agad