Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Итак у нас есть некий документ, представленный в базе данных группой записей. И есть много пользователей, которые хотят этот документ помучать. Причем пользователи почему-то хотят его помучать одновременно. Необходимо как-то заблокировать документ от редактирования, если его уже кто-то мучает. При этом документ должен разблокироваться, в случае, когда пользователь отвалился от системы. Какие я знаю варианты работы с логической единицей документ: 1. Сохранять данные в базу при любом изменении в документе и заново перезапрашивать документ целиком. Тогда пользователь всегда будет видеть последнюю версию документа и в какой-то степени может быть уверен, что его изменения так же увидят и примут к сведению. Минус в этом способе достаточно большой - может быть нарушена логическая целостность документа. 2. По завершении работы с документом выполняется короткая блокировка таблиц и документ перекрывает данные, которые на данный момент лежат в базе. Минус в подходе: "Кто последний, тот и папа". Если два пользователя работали с документом одновременно, то гораздо обиднее будет тому пользователю, который первым закрыл документ. 3. Использовать длинные блокировки. То бишь, кто первый открыл документ, тот его блокирует, а остальные могут сосать лапу (ReadOnly, например). Минусы подхода - не знаю, как это красиво реализовать на Pg SELECT ... FOR UPDATE меня не устраивает в принципе. Хотя, по номеру транзакции в cMin я могу получить, кем запись заблокирована на данный момент, тем не менее, я не могу сказать COMMIT или ROLLBACK для этой транзакции если у меня другой PID. Это как раз ситуация, когда клиент, блокировавший записи вдруг отвалился. А еще хуже будет, если процедура не проверит запись на заблокированность и попробует писать в нее. Тогда у меня будет болтаться куча клиентов, ожидающих завершения первой транзакции. Больше всего в данном случае меня бы устроил механизм семафора, причем если умирает PID, породивший семафор, семафор так же бы умирал. Так же неплохо бы прибивать такой семафор с другого PID'а, например под админом. Может есть другие решения? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.08.2006, 14:25 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Kruchinin Pahan2. По завершении работы с документом выполняется короткая блокировка таблиц С проверкой, что блокируемые данные не изменились с тех пор, как их начали редактировать. Например, ввести поле - дата последнего изменения записи и запоминать ее перед началом редактирования, а потом пытаться блокировать. Либо сравнивать все поля - запомнили перед началом, попытались заблокировать точно такую же запись. Если нет - извини, кто-то уже поработал. Kruchinin Pahan3. Использовать длинные блокировки. То бишь, кто первый открыл документ, тот его блокирует, а остальные могут сосать лапу (ReadOnly, например). Минусы подхода - не знаю, как это красиво реализовать на Pg В смысле? Как и любую другую блокировку Kruchinin PahanSELECT ... FOR UPDATE меня не устраивает в принципе. Это как раз ситуация, когда клиент, блокировавший записи вдруг отвалился. Вопрос к вам и всем знатокам - а нет ли у постгреса настройки, которая говорит - через какое время убивать неактивную сессию (как в оракле)? Kruchinin PahanА еще хуже будет, если процедура не проверит запись на заблокированность и попробует писать в нее. А кто у нас разработчик? Что значит "не проверит"? Значит ошибка в программе. А если процедура вместо того, чтобы вычесть будет умножать? Я надеюсь, у вас пользователи сами не клепают процедур? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.08.2006, 14:49 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Журнал работы с документами завести ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.08.2006, 15:03 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Я бы сделал такой комплекс мер:. Выдели те действия которые не дожны пересекаться. например - смена статуса документа если кто-то провел документ, а я пытаюсь после этого его провести - то я должен получить отлуп с пометкой- что документ уже проведен. Далее обновление делать на основе запросов в котрых участвуют все поля измененной записи. Например поменял клиента - отсылаю на сервер запрос : Update doc set id_client=new_id_client where id_doc=.. and id_client=old_id_client Если ктото до этого поменял клиента - то я ничего не изменю ( запись старая не найдется). Это можно отследить в программе и выдать соответвующее предупреждение или же просто перечитать "измененную" запись - и увидеть что она не поменялась. Все изменения делать в короткой СНАПШОТ транзакции. Что гарантирует откат в случае если паралельно кто-то меняет эту же запись . Выдавать Notify от сервера в случае изменения документа, оперативно реагировать на это путем обновления документа на клиенте. По моему этого достаточно чтобы избежать несогласовонности в документе. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.08.2006, 15:46 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Народ, у меня похожий вопрос. Только в моём случае у меня около 30-ти различных связанных между собой таблиц, много хранимых процедур и т.д. А сейчас меня попросили сделать так, чтобы два пользователя одновременно не могли апдейтить одну и ту же запись, потому что по их словам: "БД может полететь или вся система". В принципе, от одновременного создания ничего не будет? И от доступа тоже, ведь так? Мне важно предотвратить эффект именно от одновременного апдейта одной ти той же записи. Работаю я с PostgreSQL через JDBC. При коннекте к базе, происходит connection.setAutoCommit(true), и после того, как "выполнится" хранимая процедура апдейта(через CallableStatement: cst.execute()), вызывается connection.commit() и только потом connection.close(). В самой хранимой процедуре обычный оператор UPDATE. Подскажите, знающие люди, при таком апдейте необходимо принимать какие-то дополнительные меры? Действительно ли при одновременном апдейте одной и той же записи может быть экзепшн и что-то может полететь? Или же в PostgreSQL это как-то предусмотрено? а если не предусмотрено, то как быть? Спасибо большое заранее! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.08.2006, 19:51 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
mwolfЖурнал работы с документами завести Согласен. Журнал поможет во многих случаях, не только в этом. Правда есть одно но. Желательный эффект: Пользователь открывает документ на редактирование; ему сообщают, что документ уже открыт; пользователь получает документ на чтение. С Журналом все красиво работает, пока юзер не отвалился от базы с открытым документом, забыв сообщить базе, что он больше документ не держит. Как в таких случаях быть? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 05:52 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Либо сравнивать все поля - запомнили перед началом, попытались заблокировать точно такую же запись. Если нет - извини, кто-то уже поработал. Вот это как раз и некрасиво. Красивей было бы, если бы пользователю до того как он начинает мучать документ сообщили бы, что он не сможет что-то сохранить и пусть даже не пытается. А кто у нас разработчик? Что значит "не проверит"? Значит ошибка в программе. Просто система развивается "на коленке", бишь этап активной эксплуатации системы продолжается параллельно с этапом разработки. С учетом штата разработчиков, я не могу гарантировать, что какой-нибудь "атавизм" не будет писать без проверки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 05:59 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Kruchinin Pahan mwolfЖурнал работы с документами завести Согласен. Журнал поможет во многих случаях, не только в этом. Правда есть одно но. Желательный эффект: Пользователь открывает документ на редактирование; ему сообщают, что документ уже открыт; пользователь получает документ на чтение. С Журналом все красиво работает, пока юзер не отвалился от базы с открытым документом, забыв сообщить базе, что он больше документ не держит. Как в таких случаях быть? Например добавлять в журнал каждые n секунд запись мол с документом работают, а у 2,3... пользователя на клиенте каждые m секунд проверять редактируется запись или нет (m>n). Если тот кто редактировал отпадет, он через n секунд не добавит запись, а через m секунд остальные узнают что запись больше не редактируется. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 07:32 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
При отвале клиента - постгрес сразу же откатит все блокировки. Т.е.п роцесс привязанный к клиенту закроется.. Во всяком случае так должно быть. Вопрос -к тем у кого больше практики- наблюдаются ли случаи когда отвалился клиент- а сервак продолжает держать все созданные блокировки? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 10:19 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Kruchinin Pahan Либо сравнивать все поля - запомнили перед началом, попытались заблокировать точно такую же запись. Если нет - извини, кто-то уже поработал. Вот это как раз и некрасиво. Красивей было бы, если бы пользователю до того как он начинает мучать документ сообщили бы, что он не сможет что-то сохранить и пусть даже не пытается. То, что я описал, это ситуация, когда используются короткие транзакции, блокирующие запись только при применении изменений. До того, как пользователь начнет мучать документ, документ может быть еще никем не тронут и пользователю нечего сообщать. Если хотите, чтобы после начала редактирования никто более не мог трогать документ - блокируйте его в момент начала редактирования. Kruchinin Pahan А кто у нас разработчик? Что значит "не проверит"? Значит ошибка в программе. Просто система развивается "на коленке", бишь этап активной эксплуатации системы продолжается параллельно с этапом разработки. С учетом штата разработчиков, я не могу гарантировать, что какой-нибудь "атавизм" не будет писать без проверки. Какой-нибудь "атавизм" может и вашу изобретенную систему не использовать. Вообще, если у вас нет уверенности в программерах, нужно писать ядро и требовать, чтобы все остальные работали только через него. А в ядре уже организовывать все необходимые проверки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 10:25 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
domanixПри отвале клиента - постгрес сразу же откатит все блокировки. Т.е.п роцесс привязанный к клиенту закроется.. Во всяком случае так должно быть. Вопрос -к тем у кого больше практики- наблюдаются ли случаи когда отвалился клиент- а сервак продолжает держать все созданные блокировки?речь видимо не о блокировке, а об оповещении статуса записи. чтобы статус был виден снаружи, он выставляется нетранзакционно. но тогда необходим механизм сброса статуса при "неправильном" завершении сессии - без снятия флага в журнале. т.е. желателен механизм, который бы был виден снаружи (нетранзакционный), но при этом - еще и откатывался сам. видимо проверка статуса записи (заблокирована или нет) на это похожа. проверка осуществляется видимо попыткой осуществить свою блокировку. тут интересен случай, когда некто забирает документ не в транзакции и выставляет время, не вернув в которое (не подтвердив работу) теряет право на редактирование. - зачем держать коннект для таких случаев? (а это видимо должно делаться через таймер. т.е. вопрос про job-ы становится актуальным. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 10:44 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Ребят, обратите внимание и на мой вопрос, пожалуйста. Он чуть выше в этой теме. Просто создавать новую тему, я думаю, что это будет неправильно, ведь, похожая уже есть. Модеры наедут потом :) Поэтому и решил спросить тут. Это очень важно, больше спросить не у кого, поэтому на вас и уповаю :) Спасибо ещё раз заранее. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 11:03 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
J-ProНарод, у меня похожий вопрос. Только в моём случае у меня около 30-ти различных связанных между собой таблиц, много хранимых процедур и т.д. А сейчас меня попросили сделать так, чтобы два пользователя одновременно не могли апдейтить одну и ту же запись, потому что по их словам: "БД может полететь или вся система". В принципе, от одновременного создания ничего не будет? И от доступа тоже, ведь так? Мне важно предотвратить эффект именно от одновременного апдейта одной ти той же записи. Отвечаю я. Потому что сам хочу поразбираться с этим вопросом. Гляди. Основной принцип корректировки данных это: 1. SELECT 2. <<DO SOMETHING>> 3. UPDATE ([INSERT], [DELETE]) Теперь рассмотрим как разнесены 1-ый и 3-ий элементы во времени. I. В одной транзакции. Тогда пофиг, что делают другие пользователи - в PgSQL мы работаем со слепком базы на момент транзакции, поэтому не изменятся ни данные на момент селекта, и не будет повреждена целостность базы на момент update'а Пример: BEGIN ; INSERT INTO t1 (val1, val2) (SELECT val1, val2 FROM t2) ; COMMIT ; II. В двух транзакциях с "коротким" промежутком между ними. Например, работа робота. В таком разе состояние базы может измениться между транзакциями. Если мы работаем с кучей записей, может оказаться, что часть записей отмодифицирована нами, часть записей другим пользователем. Тогда, если остальные пользователи могут подождать пока робот наработается, можно просто заблокировать все выбранные нами записи "SELECT ... FOR UPDATE". Или даже залочить нужные нам таблички. III. Все так же как во втором случае, но работает пользователь. Пользователь делает SELECT, долго тупо глядит на результаты SELECT'а, затем правит пару циферок или буковок и делает UPDATE. Естественно, простая залочка записей нам не поможет. Потому что пока пользователь "долго тупо смотрит..." другие ждут выполнения приторможенного UPDATE'a этой же записи (если нажали на кнопку "сохранить" чуть пораньше. Насчет пункта III есть такая идея. Создаем табличку CREATE TABLE "Tab" ("UPid" PID, "uName" NAME, "Record" OID). Табличка содержит PID процесса пользоватиля, взявшего запись, имя пользователя и указатель на запись (Record::Oid). До захвата записи пользователь запускает функцию, которая выполняет следующий функционал: 1. Проверяет в табличке те PID'ы с теми пользователями, которых сейчас нет в системе. И прибивает отвалившихся пользователей. 2. Проверяет нет ли в табличке кого-нибудь, кто держал бы нужную нам запись. Если кто-то есть, поднимает Exception или еще как ругается. 3. Если запись никем не заблокирована, создает новую строчку в этой табличке куда запишет ID процесса, ID пользователя и ID строки, таблицы или логического объекта (уже от вкуса программиста зависит). 4. Возвращает клиенту флажок типа все в порядке. Тока надо не забывать прибивать залочки, когда пользователь закрыл документ. И еще фишка. Пользователь может некорректно закрыть документ, так что процедура удаления залочки не отработает. При этом, коннект может остаться в живых (для Shared коннекшнов это нормально). Тогда чтоб распинать документ надо будет ручками почистить табличку, или выгнать этого пользователя из программы в принципе. Ж;)) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 13:21 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Уважаемый Kruchinin Pahan ! Огромное спасибо за столь длинный ответ. Странно, я всё время думал, что для того, чтобы обновить запись в таблице, есть только один способ - UPDATE. Если честно, то я лишь полгода работаю с PostgreSQL. Раньше работал с Microsoft SQL. Там, как мне кажется, всё намного проще... Не знаю. Вот сейчас почитал Ваш ответ, если честно, не совсем понял в суть. Можно как-то попроще? Я обьясню точнее, что у меня происходит: при каждой операции, будь то выборка записей или апдейт, происходит отдельный коннект, потом коммит, потом дисконнект. Поэтому, Ваше предложение: Kruchinin PahanПользователь делает SELECT, долго тупо глядит на результаты SELECT'а, затем правит пару циферок или буковок и делает UPDATE. кажется мне неприменимым для моей ситуации. Или я просто чего-то не понял? Т.е. чтобы проапдейтить, к примеру, какого-то юзера, происходит следующее: коннект к базе, используя имя юзера и пароль вызов хранимой процедуры выборки всех юзеров из базы потом делаем коммит закрываем коннекшн разбираем пришедший резалт сет и показываем юзеру список полученный пользователей пользователь выбирает одного из списка и жмёт апдейт, ему открывается отдельная страничка с текущими данными пользователя он меняет их, как ему хочется и жмёт "Запись в систему", при этом: коннект к базе, используя имя юзера и пароль вызов хранимой процедуры апдейта выбранного пользователя в базе потом делаем коммит закрываем коннекшн Вот. В таком случае возникают вопросы: 1. Что можно сделать, чтобы предотвратить сбой БД при одновременной попытке двух пользователей проапдейтить одинаковую запись в базе? И вообще, нужно ли это при таком подходе? Или же PostgreSQL не полетит, а как-то разберётся с этим сама, своим механизмом? 2. Не надо ли ничего предусматривать на тот случай, если два пользователя вызовут одну и ту же хранимую процедуру ВЫБОРКИ? Или тут полегче и моно всё оставить, как есть? Спасибо ещё раз за участие и за помощь! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.08.2006, 19:39 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
J-ProУважаемый Kruchinin Pahan ! 1. Что можно сделать, чтобы предотвратить сбой БД при одновременной попытке двух пользователей проапдейтить одинаковую запись в базе? И вообще, нужно ли это при таком подходе? Или же PostgreSQL не полетит, а как-то разберётся с этим сама, своим механизмом? На самом деле, никакого "сбоя" БД в PG быть не должно. Все дело в конкурентных транзакциях. Смысл в том, что ПГ хранит все версии одной и той же строки в БД (до VACUUM). Когда ты делаешь SELECT ты выбираешь текущую версию, даже если уже существует более поздняя версия этой строки, от другого пользователя, но транзакция этого пользователя еще не завершилась. Когда ты делаешь UPDATE, создается копия текущей (на момент этой транзакции) строки с соответствующей заменой значений, указанных в запросе. Даже если кто-то делает update одновременно, сама БД отреагирует на это нормально. Правда, в конце концов в базе данных останется видимой запись со старшим номером транзакции. Вобщем, смысл в том, что сколько бы ты ни update'ил запись, физическая целостность БД при этом не пострадает и ничто не полетит. Другой вопрос в том, что для пользователя более важной является логическая целостность. Предположим есть кладовщик и менеджер продаж, которые одновременно открыли одну и ту же накладную. Менеджера клиенты попросили заменить в накладной болт М6 на гайку с резьбой. А кладовщик в это же время проставляет партии товара. Документ сделал SELECT и обоим показывается болт М6. Кладовщик ставит партию болт1М6, а менеджер меняет болт на гайку. По закрытии документа проходит два UPDAT'а. Все рады, пока не откроют документ по новой. Оказывается, что мы продали гайку из партии болтов М6. Это на самом деле большая проблема, использует ли база данных метод конкурентных транзакций (PgSQL) или метод блокировок таблиц (MsSQL) - без разницы. J-Pro 2. Не надо ли ничего предусматривать на тот случай, если два пользователя вызовут одну и ту же хранимую процедуру ВЫБОРКИ? Или тут полегче и моно всё оставить, как есть? На самом деле любой БД пофиг что делают пользователи. Тем или другим способом такие вещи регулируются. Например, я делаю SELECT, пока он выполняется, другой пользователь делает INSERT. В MsSQL транзакция на INSERT будет приторможена, пока не выполнится моя транзакция на SELECT. В PG транзакция на INSERT успешно завершится, но результаты будут мне не видны, потому что транзакция на INSERT имеет старший по отношению к моей номер и добавленная строчка находится в будущем по отношению к моей транзакции. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.08.2006, 06:15 |
|
||
|
Совместный доступ к группе записей (документу)
|
|||
|---|---|---|---|
|
#18+
Kruchinin Pahan1. SELECT Здесь при желании (поработать) можно поставить таймер. Скажем, каждую минуту если человек за компом не ушел пить пиво (т.е. или (а) были движения мышью или (б) он чего-то изменил /попробовал изменить/), повторять запрос и светить изменения. Kruchinin Pahan2. <<DO SOMETHING>> 3. UPDATE ([INSERT], [DELETE]) А это лучше делать в отдельной процедуре. Но не "стащить с огорода 3(три) морковки", а "попытаться стащить...". Т.е. отдельной транзакцией берем не то, что он запросил, а проверяем и берем то, что есть на данный момент и отвечает апетиту клиента. А ему возвращаем ноль либо размер неудовлетворенной заявки. Живем в конкурентной среде и точно такой же Иван Петрович нажал на Enter раньше. Потому что меньше курит и чаще жмет на клавиши, что при равных правах дает ему преимущество. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.08.2006, 08:36 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=33896408&tid=2006185]: |
0ms |
get settings: |
9ms |
get forum list: |
19ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
135ms |
get topic data: |
11ms |
get forum data: |
2ms |
get page messages: |
76ms |
get tp. blocked users: |
1ms |
| others: | 264ms |
| total: | 523ms |

| 0 / 0 |
