Pull to refresh

Comments 32

UFO just landed and posted this here
— Как проверять, когда со строкой работают несколько пользователей? Какие варианты есть?

В MSSQL есть столбец типа timestamp, в pg можно заюзать xmin, например. Отдаём на форму его значение, при апдейте проверяем не только ключ, но и сравниваем с xmin. Если кто-то изменил строчку — не обновим ничего, сообщаем пользователю (а он уж пусть решает, насильно перенакатить, бросить всё, попытаться смёржить).
Не надо xmin. Это внутренная механика, не используйте ее в своих целях (если, конечно, не хочется развлечений при обновлениях). Не хочется проверять все поля — сделайте свой номер версии.
Ну а что делать, если в PG нет встроенных средств :( Если использование сущности ограничено, то можно и своё версионирование написать, но потом придёт какой-нибудь разработчик, и забудет в каком-нибудь апдейте проинкрементить версию. В результате всё замечательно «сломается», хотя работать будет, но будет бага вида «у меня пропали данные», которую вообще не возможно будет отследить.
Уж лучше всё упадёт при обновлении и можно накрыть это костылями, чем будет странно себя вести из-за ошибки программиста в каком-нибудь второстепенном модуле.
Простите, а какие встроенные средства вы хотели бы видеть? Чем вариант с хешом от всех колонок не нравится?
В MSSQL есть столбец типа timestamp (и нет, там не время). В результате при любом обновлении записи значение этого столбца меняется автоматически. Ничего не надо считать ручками, нельзя забыть его обновить. В postgre для этих целей можно использовать xmin, но он считается не очень труЪ способом.
Ну наверное да, неплохо, что есть.
Дык сделайте поле и повесьте триггер, проблема-то.
А если боитесь что-то забыть, то все это можно автоматизировать, вплоть до создания триггеров на новых таблицах из событийного триггера.
Ну еще проще смотреть md5(t::text), разница по большому счету просто синтаксическая.
Да понятно что проще, кто ж спорит.
Не стоит это использовать для данной задачи.
Представьте, пользователь открывает форму на редактирование и… уходит на обед. Строчка залочена. Больше никто не может ничего с ней сделать.
Так незачем держать транзакцию открытой когда пользователь открыл форму. Транзакцию открывают когда пользователь сохраняет форму.
select for update блокирует чтение строки другими транзакциями.
А смысл этого действия? Форму открыли два пользователя в 12:00. Редактируют, первый сохранил в 12:05, второй в 12:10 и затёр все действия первого. Чем нам в этой ситуации поможет SELECT FOR UPDATE?
А для этого либо
  • проверяют поля до/после
  • timestamp
  • version


select for update нужен например что бы другие транзакции не делали ненужные действия, а потом долго их не откатывали.
Ну что вы, чтение не блокируется. Блокируется только изменение.
Но транзакцию, конечно, все равно не надо держать открытой.
Разве SELECT FOR UPDATE не для того что бы блокировать чтение данной строки для паралельных SELECT FOR UPDATE?
SELECT FOR UPDATE же не просто читает, он блокирует. Просто чтение (SELECT) будет работать, а SELECT FOR UPDATE или UPDATE — будут ждать.
select for update не блокирует чтение (т.е. select). Он блокирует запись или select for update другими пользователями.
Собственно для задачи гарантированного избавления от совместных правок это и придумано.
Как мне показалось в докладе обсуждается именно проблема совместных правок.

Впрочем топик про Pg. И, судя по всему, в нем нельзя на уровне базы гарантировать неизменяемость данных другими транзакциями на необходимое время.
Ну это как бы логично — кто первый успел, того и тапки. Хуже будет, если пользователь 1 открыл форму и ушёл на обед. Пользователь 2 открыл ту же форму, внёс изменения и записал данные. Пользователь 1 вернулся с обеда, внёс в форму данные и при попытке записать данные система говорит, что пользователь 2 уже изменил данные. Поэтому нужно переоткрыть форму (перечитать данные из бд) и все, что вносил пользователь 1 в форму, нужно теперь внести заново
Хуже будет, если пользователь 1 открыл форму и ушёл на обед

Что вы тут предлагаете? Не давать редактировать форму никому, или просто сделать хороший код, который это как-то обрабатывает. Второй подход отличный, но очень дорогой в плане времени программистов (форм много, все разные, ситуация не очень частая).
Это хороший вопрос. Я скажу лишь как сейчас реализовано, например в 1С. До недавнего времени, если пользователь открыл форму документа, то никто больше не мог работать с этим документом. Теперь идет проверка самой платформой (не на уровне бд) признака модифицированности. Если пользователь внес изменения и не записал их — просмотр и редактирование документа по прежнему невозможно, а если модифицированности формы нет, то другие пользователи могут работать с документом. То есть, если пользователь 1 открыл форму и ушел на обед, при этом не внеся никаких правок, то пользователь 2 спокойно может работать, если правки пользователь 1 успел сделать — то пользователь 2 работать с документом не сможет
Это плохое решение. Пользователь может не на обед, а куда-то убежать по делам (любимый хомячок простудился) и банально позвонить другому с просьбой доделать. Может просто случайно нажать какую-то кнопку (сохранять не планировал) и уйти домой. В небольшой организации это может решиться организационными методами и пенделями работникам, но больше шансов, что пендели получать разработчики.
Мы, разработчики, нередко полагаем, что можем программным методом направить, так сказать, пользователей на путь истинный. Написать свой «ИИ» чтобы данные вводились только корректные и бизнес процесс шёл идеально. Но в реальности самыми действенными способами оказываются именно организационные. Главное не забывать, что лучше всего на человека влияет другой человек, а любое ограничение системы пользователь найдёт как обойти
— Как проверять, когда со строкой работают несколько пользователей? Какие варианты есть?

— Во-первых, можно перед показом строки в форме вЫчитать значения всех колоночек и убедиться, что они не поменялись. Второй вариант, более удобный: высчитать хэш на всех
колонках, тем более, что колонки там могут быть большие и толстые. А хэш не такой большой.

Серьезно, это вопрос на конференции?
Абсолютно серьезно. А что такого? Вон выше select for update предлагают.
Поправьте меня, может, я не понимаю.
Все эти select for update — это же про то, как блокировать данные в транзакции при изменении (т.е. сначала select, какая-то обработка, тут же update). А не про то, что Вася открыл окно, select-ом for update выбрал и заблокировал строку на длительное время, а потом через час сделал update.
В вопросе речь идет про non-lock concurrency control. Это когда на уровне логики приложения проверяется, не изменена ли запись кем-то относительно момента, когда мы ее вывели в окно. И это не в транзакции.
Мне кажется, это не вопрос о PostgreSQL.
Все эти select for update — это же про то, как блокировать данные в транзакции при изменении...
Да, все верно.
Мне кажется, это не вопрос о PostgreSQL.
Безусловно, но тем не менее иметь в виду это необходимо.

Партиции для архивных данных работают прекрасно. Делал так, например, базу ФИАС разбивая на партиции по регионам. Рекурсивный CTE вытаскивает данные очень быстро.

у нас еще есть max idle in transaction

Возможно, имелось ввиду idle_in_transaction_session_timeout?
Sign up to leave a comment.