Здравствуйте, IB, Вы писали: P_K>>Надо, согласен. Но сложность растёт как снежный ком и это всё быстро выходит из под контроля, когда оно на уровне базы. IB>Если сложность растет от работы на уровне хранилища, значит вы что-то делаете не так, должно быть ровно наоборот.
Я имел в виду когда блокировки рулятся транзакциями на уровне базы, то они, блокировки, быстро выходят из-под контроля.
Допустим всё приемлемо работает на таких блокировках. Тут появляется новая фича, в перечень проверок добавляется чтение новой сущности (а значит и блокировка). Потом добавляется ещё одна фича, потом ещё одна. И это не в одно бизнес-действие, а в несколько. В итоге проверки блокируют условно пол-базы и "привет, дедлоки!"
Выходит из-под контроля — потому что писателям бизнес-кода неизвестно чего там заблокирует база. Это отдельный вопрос, для которого наверно нужен грамотный DBA.
P_K>>Похоже что требуется архитектурное решение, делающее по сути те же блокировки что умеет СУБД, но в терминах бизнес-слоя. Надеюсь что в итоге блокировки станут более предсказуемыми и обозримыми. IB>Наоборот, в этом случае все вообще выйдет из под контроля, либо будет строго однопоточным и не масштабируемым. Хранилище — это единственное место где можно более-менее адекватно разрулить проблемы с синхонизацией данных.
Вот тут позволю себе не согласиться. Пусть наш бизнес-код в serializable-транзакции вычитывает какую-то сущность из базы (несколько строк из пар таблиц). Что заблокирует база? Только прочитанные строки? Какие-то свои страницы (т.е. заранее непредсказуемый набор сущностей)? Всю таблицу (все сущности)? Вот я не могу ответить на этот вопрос, это надо очень глубоко закапываться в базу. То есть для меня автоматические блокировки хранилища — вещь непредсказуемая, а значит такое решение адекватным не назовёшь.
Если блокировки не автоматические, предсказуемые, то единственным аргументом против базы я вижу вопрос производительности. Зачем бегать в базу, если можно разрулить в памяти? Масштабируемость (несколько app-серверов) на требуется.
IB>В принципе, в каждой БД есть возможность воспользоваться механизмом блокировок для нужд прикладного слоя. Для сиквела это пара процедур sp_getapplock/sp_releaseapplock, но это ровно про то же самое, просто позволяет синхронизировать еще и сущности которые напрямую в БД не хранятся.
Интересно, не знал, спасибо.
Здравствуйте, Poul_Ko, Вы писали:
P_K>Или не то имелось в виду?
Это, если все вычитанные данные сохранятся с самим заказом. Если нет — берутся id записей истории и подставляются в заказ. Т.е. заказ сохраняется строго в том состоянии, в каком его подтвердил пользователь.
P_K>Условия меняются после подтверждения — если они противоречат уже подтверждённым заказам, то ПО отвергает изменения, юзеры должны сначала устранить проблему, например, отменить конфликтующие заказы. Но они должны это сделать явно.
Вот это не сработает. Нельзя "отменить конфликтующий заказ" простым велением левой ноги разработчика. Или такой биз-процесс обоснован реальными нуждами бизнеса и описан в ТЗ, или тот, кто занимался анализом требований схалтурил
А если онобоснован, то в 99% случаев там будет или неявное согласие с обновлённой офертой (как меняют договоры большинство провайдеров), или заключение допсоглашения (явное подтверждение изменений заказа).
S>>В тех редких ситуациях, когда это не так, производится доппроверка перед заключением договора, которая уменьшает окно рассогласования до 2..3 минут. P_K>Что такое "окно рассогласования"?
Грубо говоря — ожидаемое время между "получили данные" и "сохранили обратно". Т.е. проверять, при неудаче сохранения (что-то поменялось) показать обновлённые данные пользователю и так по новой.
P_K>При коррекции условий договора происходит проверка всех подтверждённых заказов по данному договору, если есть заказы, которые идут в разрез с новыми условиями, то коррекции не происходит, список показывается пользователю и бизнес-операция завершается. Пользователь должен исправить заказы и попытаться ещё раз изменить условия договора.
Ну, раньше про "показывается пользователю" речи не шло, речь шла про блокировки.
В случае "показывается пользователю" блокировки не катят по понятным причинам, только optimistic concurrency.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Poul_Ko, Вы писали:
P_K>>Или не то имелось в виду? S>Это, если все вычитанные данные сохранятся с самим заказом. Если нет — берутся id записей истории и подставляются в заказ. Т.е. заказ сохраняется строго в том состоянии, в каком его подтвердил пользователь.
А зачем? Я в том плане что это не требуется бизнесу. Бизнес должен видеть — заказ подтверждён, заказ по договору Х, значит условия договора и заказ не противоречат друг другу. Точка. Никаких версий и историй записей им не нужно.
P_K>>Условия меняются после подтверждения — если они противоречат уже подтверждённым заказам, то ПО отвергает изменения, юзеры должны сначала устранить проблему, например, отменить конфликтующие заказы. Но они должны это сделать явно. S>Вот это не сработает. Нельзя "отменить конфликтующий заказ" простым велением левой ноги разработчика. Или такой биз-процесс обоснован реальными нуждами бизнеса и описан в ТЗ, или тот, кто занимался анализом требований схалтурил
Причём здесь разработчик? Заказ отменяется пользователем. Пишу же, пользователи должны это сделать явно!
S>>>В тех редких ситуациях, когда это не так, производится доппроверка перед заключением договора, которая уменьшает окно рассогласования до 2..3 минут. P_K>>Что такое "окно рассогласования"? S>Грубо говоря — ожидаемое время между "получили данные" и "сохранили обратно". Т.е. проверять, при неудаче сохранения (что-то поменялось) показать обновлённые данные пользователю и так по новой.
А как отловить вот это неудачу сохранения ("что-то поменялось") в многопоточной среде без блокировок?
P_K>>При коррекции условий договора происходит проверка всех подтверждённых заказов по данному договору, если есть заказы, которые идут в разрез с новыми условиями, то коррекции не происходит, список показывается пользователю и бизнес-операция завершается. Пользователь должен исправить заказы и попытаться ещё раз изменить условия договора. S>Ну, раньше про "показывается пользователю" речи не шло, речь шла про блокировки.
В чём проблема с показыванием? Меняем договор, для проверки ищем все заказы по нему. Они у нас есть, уже загружены, нашли конфликтующие — всё, абзац, изменения не принимаются, бизнес-операция завершается, её результат — "не удалось + список заказов". Показывание и действия пользователя по исправлению идут своим чередом, как обычные операции, вне бизнес-операции изменения договора. Об этом было написано же.
Здравствуйте, Poul_Ko, Вы писали:
S>>Это, если все вычитанные данные сохранятся с самим заказом. Если нет — берутся id записей истории и подставляются в заказ. Т.е. заказ сохраняется строго в том состоянии, в каком его подтвердил пользователь. P_K>А зачем? Я в том плане что это не требуется бизнесу. Бизнес должен видеть — заказ подтверждён, заказ по договору Х, значит условия договора и заказ не противоречат друг другу. Точка. Никаких версий и историй записей им не нужно.
Требуется. К примеру, для розничной торговли см п. 1 ст. 500 ГК РФ
1. Покупатель обязан оплатить товар по цене, объявленной продавцом в момент заключения договора розничной купли-продажи, если иное не предусмотрено законом, иными правовыми актами или не вытекает из существа обязательства.
Т.е. храним строго то, что подтвердил пользователь, и, опционально, при сохранении делаем проверку и просим подтвердить новую цену. Иначе никак.
S>>Вот это не сработает. Нельзя "отменить конфликтующий заказ" простым велением левой ноги разработчика. Или такой биз-процесс обоснован реальными нуждами бизнеса и описан в ТЗ, или тот, кто занимался анализом требований схалтурил P_K>Причём здесь разработчик? Заказ отменяется пользователем. Пишу же, пользователи должны это сделать явно!
Опс и прошу прощения. Неверно понял
S>>Грубо говоря — ожидаемое время между "получили данные" и "сохранили обратно". Т.е. проверять, при неудаче сохранения (что-то поменялось) показать обновлённые данные пользователю и так по новой. P_K>А как отловить вот это неудачу сохранения ("что-то поменялось") в многопоточной среде без блокировок?
Через optimistic concurrency — update проходит только если не поменялось состояние заказа (например, чексумма).
S>>Ну, раньше про "показывается пользователю" речи не шло, речь шла про блокировки. P_K>В чём проблема с показыванием?
Нельзя удерживать блокировку на время показа. Пользователь затормозил на 5 минут — все прочие связанные операции встали на те же 5 минут.
Здравствуйте, Sinix, Вы писали: S>Требуется. К примеру, для розничной торговли см п. 1 ст. 500 ГК РФ
Не применимо. Здесь ситуация другая, требования я описал, давайте своих добавлять не будем
S>>>Грубо говоря — ожидаемое время между "получили данные" и "сохранили обратно". Т.е. проверять, при неудаче сохранения (что-то поменялось) показать обновлённые данные пользователю и так по новой. P_K>>А как отловить вот это неудачу сохранения ("что-то поменялось") в многопоточной среде без блокировок? S>Через optimistic concurrency — update проходит только если не поменялось состояние заказа (например, чексумма).
А состояние заказа и не поменяется. Поменяется состояние связанного договора.
Или предлагаете при изменении договора менять версии всех связанных с ним заказов, даже неподтверждённых? Как-то странно это будет...
S>>>Ну, раньше про "показывается пользователю" речи не шло, речь шла про блокировки. P_K>>В чём проблема с показыванием? S>Нельзя удерживать блокировку на время показа. Пользователь затормозил на 5 минут — все прочие связанные операции встали на те же 5 минут.
Блокировки не будет. Список заказов — это результат операции, а не её часть. На время показывания ничего не блокируется, да и времени этого нет. Это просто окно "Упс! Не можем изменить даты действия договора — по нему есть подтверждённые заказы, попадающие в интервал когда договор перестаёт действовать. Это заказы №№1, 2 и 5.", и одна кнопка "Закрыть".
Здравствуйте, Poul_Ko, Вы писали:
P_K>// Почему здесь Agreement? Подтверждаем-то мы заказ!
Эээ.. Да я запутался в твоей модели данных. Но какая разница-то? Суть та же. Версию менять и проверять надо у того, что зависит от изменения данных:
BEGIN TRANS;
UPDATE Agreement SET startDate = ... WHERE id=1;
UPDATE Order SET version=version+1 WHERE agreementId=1;// заметь, тут несколько ордеров может быть изменено.
COMMIT;
Транзакции атомарны, поэтому их можно использовать для обеспечения казуальности.
SELECT version, ... FROM Order...;
var currentVersion = version;
//check
//check
SELECT startDate, ... FROM Agreement...;
//check
//...sloooow check....
//check
UPDATE Order SET confirmed='YES' WHERE version=currentVersion...
А этот процесс не обязательно должен быть в одной транзакции — каждая sql-команда может выполняться сама по себе — транзакции будут короткоживущими, что есть хорошо.
P_K>·>Ну и модифицирующие операции (все или как минимум те, которые могут влиять на проверки) должны изменять версию: P_K>Это классика оптимистической блокировки, но работает она в пределах одного агрегата, а у нас здесь два (в реальности конечно больше)...
Так оно обобщается до произвольного числа агрегатов.
Можно даже версировать несколько сущностей, а потом атомарной операцией (т.е. обернутой в транзакцию) делать проверку совпадения всех версий и SET confirmed='YES' если всё совпало.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Poul_Ko, Вы писали:
S>>Требуется. К примеру, для розничной торговли см п. 1 ст. 500 ГК РФ P_K>Не применимо. Здесь ситуация другая, требования я описал, давайте своих добавлять не будем
Если бизнес работает с покупками, то рано или поздно подобное требование точно появится. Аналогичные правила торговли есть практически во всех странах.
P_K>Или предлагаете при изменении договора менять версии всех связанных с ним заказов, даже неподтверждённых? Как-то странно это будет...
Угу. Или любой другой способ, который позволит определить конфликт при сохранении. Иначе уведомить клиента об изменениях условия договора будет проблематично.
Здравствуйте, ·, Вы писали: .>Версию менять и проверять надо у того, что зависит от изменения данных
Теперь идею понял.
В реальности изменения будут каскадными — меняем договор -> меняются версии связанных заказов -> меняются версии других связанных сущностей... Где-то в этой цепочке могут появляться кольца.
Интересно подумать как будет решаться ситуация когда меняется сама связь, например, для заказа выбирается другой договор и нужно проверить что он подходит.
Или когда условие имеет вид "чего-то не существует" (мы же не можем менять версию того, чего нет). Наверно придётся вводить какие-то дополнительные сущности или флаги.
В общем, спасибо, отправная точка есть, нужно будет это всё хорошо обмозговать с товарищами.
Здравствуйте, IB, Вы писали:
IB>Для всего этого не нужно писать свой менеджер блокировок. В нормальных базах обычно предоставляется механизм позволяющий получить доступ к менеджеру блокировок базы и воспользоваться его услугами для блокировки прикладных объектов. Гораздо правильнее воспользоваться им, если уж возникнет такая нужда, чем городить собственный менеджер.
Да, если приложение жестко привязано к одной СУБД. Нет, если необходима поддержка нескольких СУБД, в том числе и тех, которые такого механизма не предоставляют. В случае 1С это так.
W>>Но за это приходится платить дорогую цену. Все изменения бизнес объектов должны идти через этот менеждер блокировок. Например, мы не можем выполнить сложный многострочный UPDATE или DELETE, так как наш менеджер блокировок не может проверить, не относятся ли затронутые им строки к заблокированным объектам. Из-за этого сильно страдает производительность на запись. IB>Отдельный плюс менеджера блокировок который встроен в БД состоит в том, что о нем знают транзакции БД.
Здравствуйте, Poul_Ko, Вы писали:
P_K>Спасибо, интересно. P_K>Если я правильно понял, то суть решения в исключении источника проблемы — многопоточного исполнения. Все операции выполняются последовательно, вокруг этого накручивается некая инфраструктура, повышающая производительность. P_K>Боюсь что для проекта в его текущем состоянии переход на такую модель потребует слишком много сил и времени.
Можно поэтапно перейти. Начать с того чтобы просто ввести очередь событий, затем в нее писать, не меняя функциональности, затем научиться проигрывать события и поэтапно переводить проект на новые рельсы.
Здравствуйте, Poul_Ko, Вы писали:
P_K>Применение — это коммит?
да
P_K>"Подтверждения договора" — нет такого в бизнес-процессе, имелось в виду подтверждение заказа?
пардон, везде вместо договора имелся в виду заказ.
P_K>
P_K>if (GetActualContractVersion(contract.Id) == contract.Version) then CommitTransaction() else RollbackTransaction();
P_K>
P_K>По идее вся последняя строчка должна отработать атомарно прямо на уровне базы, тогда решение будет рабочее, согласен. Но как её такую сделать?
да, ровно это я и имел в виду (как уже объяснили ниже). с версиями заказа не нужно блокировать всю базу для проверки его статуса, достаточно чтобы с момента начала проверки версия заказа не изменилась, тогда изменение статуса заказа на "подтвержден" можно сделать с блокировкой таблицы заказов (или даже конкретного заказа в таблице) в хранимке или в коде. профит в том, что эта операция короткая и не затрагивает/не блокирует другие таблицы.
Здравствуйте, Poul_Ko, Вы писали:
.>>Версию менять и проверять надо у того, что зависит от изменения данных P_K>Теперь идею понял. P_K>В реальности изменения будут каскадными — меняем договор -> меняются версии связанных заказов -> меняются версии других связанных сущностей... Где-то в этой цепочке могут появляться кольца.
Кольцо можно разомкнуть введя дополнительную версируемую сущность, объединяющую элементы кольца.
P_K>Интересно подумать как будет решаться ситуация когда меняется сама связь, например, для заказа выбирается другой договор и нужно проверить что он подходит.
Да то же самое:
UPDATE Order SET agreementId=2, Version=Version+1 WHERE id=12345;
P_K>Или когда условие имеет вид "чего-то не существует" (мы же не можем менять версию того, чего нет). Наверно придётся вводить какие-то дополнительные сущности или флаги.
Да всё то же:
INSERT INTO AgreementDetail(agreementId, etc...) VALUES(1, data...);// или DELETE FROM...
UPDATE Order SET Version=Version+1 WHERE agreementId=1;
Т.е. если AgreementDetail не существует — ты это увидишь что его нет в процессе проверок. Если он добавился (или удалился) конкурентно — это изменит версию ордера и вызовет откат подтверждения.
Одно плохо — надо не забывать изменять версию договора при изменении чего либо что хоть как-то может повлият на его подтверждение — это никак не проверяется явно. А если забыл — будут труднообнаружимые баги. Иначе говоря, доказать корректность системы — очень тяжело. Например, кто-то добавил код, который модифицирует поле AgreementDetail, но забыл пнуть версию соответсвующих договоров — бага — и фиг найдёшь.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Poul_Ko, Вы писали:
P_K>Допустим всё приемлемо работает на таких блокировках. Тут появляется новая фича, в перечень проверок добавляется чтение новой сущности (а значит и блокировка). Потом добавляется ещё одна фича, потом ещё одна. И это не в одно бизнес-действие, а в несколько. В итоге проверки блокируют условно пол-базы и "привет, дедлоки!"
Нет, если с базой работать нормально. Тут точно так же как в прикладном коде, если писать не оглядываясь на то что уже сделано, и что и как работает, то рано или поздно полезут побочные эффекты. А если понимаешь как все устроено, и все относительно чисто спроектировано, то никаких проблем с изменениями нет.
P_K>Выходит из-под контроля — потому что писателям бизнес-кода неизвестно чего там заблокирует база. Это отдельный вопрос, для которого наверно нужен грамотный DBA.
Не DBA, а разработчик, который знает что делать с базой... Вот все-таки странно, почему считается, что прикладной код нужно заморачиваться и писать аккуратно, а база магическим образом сама все правильно сохранит.
P_K>Вот тут позволю себе не согласиться. Пусть наш бизнес-код в serializable-транзакции вычитывает какую-то сущность из базы (несколько строк из пар таблиц). Что заблокирует база? Только прочитанные строки? Какие-то свои страницы (т.е. заранее непредсказуемый набор сущностей)? Всю таблицу (все сущности)? Вот я не могу ответить на этот вопрос, это надо очень глубоко закапываться в базу.
Вот именно. Проблема не в том, что база непредсказуема, а в том, что вы не хотите изучить этот вопрос и понять как работает база, чтобы понимать что и в каком случае будет блокироваться.
P_K>Если блокировки не автоматические, предсказуемые, то единственным аргументом против базы я вижу вопрос производительности. Зачем бегать в базу, если можно разрулить в памяти? Масштабируемость (несколько app-серверов) на требуется.
Если не требуется масштабируемости, то вопрос производительности не должен волновать.
Простое решение в лоб — гоните все ваши зменения через один глобальный мьютекс, должно быть норм, дешево и сердито. Писать же свой менеджер блокировок, особенно не имея преставления как это работает в базах... Да проще разобраться как БД работает.
Здравствуйте, wildwind, Вы писали:
W>Да, если приложение жестко привязано к одной СУБД.
Не жестко к одной СУБД, а нет требования работать одновременно с несколькими СУБД. А приложений без таких требований 99.9%
W> Нет, если необходима поддержка нескольких СУБД, в том числе и тех, которые такого механизма не предоставляют. В случае 1С это так.
Именно это я и имел ввиду, когда говорил, что у 1С это не от хорошей жизни. Но написание собственного менеджера блокировок задача совсем не тривиальная. Топикстартер не 1С же пишет.
W>Да, но в вышеописанном сценарии это не помогает.
Должен помогать, поскольку используется все тот же менеджер блокировок, то он как раз знает, какие строки относятся к заблокированным объектам. Иными словами, ваше требование про изменение бизнес-объектов через менеджер блокировок выполняется автоматически.
Здравствуйте, IB, Вы писали:
IB>Здравствуйте, Poul_Ko, Вы писали:
IB>Писать же свой менеджер блокировок, особенно не имея преставления как это работает в базах... Да проще IB>разобраться как БД работает.
В принципе он не так сложен, почти для всего хватит такой модели:
//Получение блокировки public void Lock(Object data,Write/Read mode,Object owner)
//снятие всех блокировок данного владельцаpublic void UnLock(Object owner);
Ответственность за исполнение блокировок лежит на клинском коде, т.е. всегда прежде чем трогать объект, получаем на него блокировку. А вот менеджер транзакций это уже более сложная задача.
Здравствуйте, Poul_Ko, Вы писали:
P_K>Всем доброго
P_K>Сейчас озвучу проблему, наверняка я не первый кто с ней сталкивается и решения уже давно известны, но видимо они мне не попадались или не запомнились.
P_K>Речь идёт о задаче обеспечения неизменности состояния бизнес-объектов до конца бизнес-операции в многопользовательской среде. P_K>Представим что есть какая-то операция, по бизнес правилам она может быть успешно выполнена только при определённом состоянии каких-то объектов. Как мы это реализуем? В коде сначала читаем эти объекты, проверяем их состояние, и если оно соответствует бизнес-правилам, то выполняем операцию. В многопользовательской среде здесь могут быть проблемы: состояние проверенных объектов может измениться между чтением объектов и выполнением операции, что по сути это приведёт к выполнению операции с нарушению бизнес-правил. Серьёзность такого нарушения может варьироваться — иногда это допустимо, а иногда нет (на одно место продано два билета). P_K>Для избежания такой ситуации логично выполнять блокировку прочитанных объектов до конца операции так, чтобы никто другой не мог изменить их состояние.
P_K>Здесь не идёт речь о проверке состоянии самого изменяемого объекта — решение через "оптимистическую блокировку" известно. Я говорю о стабильности состояния других логически связанных сущностей, которые сами не изменяются операцией.
P_K>Первое решение, которое в принципе уже работает, это использование serializable-транзакций на базе. Здесь по сути все блокировки выполняет база. Масштабы и объём блокировок в базе в целом слабопредсказуемы, чтобы как-то на них повлиять надо плотно садиться за структуру базы и запросы. P_K>У этого решения имеются ещё недостатки: появляются дедлоки по мере роста нагрузки и количества вовлечённых таблиц, не охватывает данные, которые не читаются из базы (находятся в кеше — справочники).
P_K>Какие другие решения можете посоветовать?
Философски — никаких других решений нет. Вы приводите пример конкурирующих изменений. Все способы решения этой проблемы давно известны.
Отличаются только детали реализации.
К примеру, "дедлок", которого вы так боитесь — это, фактически, обнаружение конфликта изменений. Его проявление в мире пессимистичных блокировок.
Какой бы способ вы ни выбрали, у вас всё равно возможна ситуация "ой, между тем, как мы показали вам цену, и вашим нажатием на кнопку Save, произошли изменения. Будете повторять?".
В pessimistic locking это будет как раз deadlock. В Optimistic locking это будет "расхождение таймстампов".
Ваше упоминание про optimistic locking связано не с проблемами OL как такового, а с его стандартной неверной реализацией.
Честная реализация OL должна трекать не только записи, но и чтения. По очевидным причинам.
Но это — очень дорого и неудобно. Поэтому вместо честного OL обычно применяют убогий. А работает он только потому, что применяется, как правило, к системам, где есть однонаправленная зависимость между данными. То есть если у нас есть конфликтующее изменение, то оно в конкурирующей транзакции обязано примениться и к нашему объекту. Ну, типа при внесении изменения в прайс-лист, в той же транзакции подправляются и все неподтверждённые заказы.
И при попытке сделать заказ подтверждённым, мы налетаем на расхождений версий заказа.
Наиболее конструктивный способ — переносить как можно больше логики в базу, и опираться на её транзакции. Чтобы время "пересечений" операций друг с другом было меньше.
Часто это решение ассоциируется со словосочетанием "логика в хранимках". Это необязательно, можно и современными средствами пользоваться, но промежуток между чтением данных и их использованием должен быть как можно короче.
В оптимистике это уменьшает количество откатов, в пессимистике уменьшает время простоя на ожидании блокировок и частоту дедлоков.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
P_K>>Какие другие решения можете посоветовать? S>Философски — никаких других решений нет. Вы приводите пример конкурирующих изменений. Все способы решения этой проблемы давно известны. S>Отличаются только детали реализации. S>К примеру, "дедлок", которого вы так боитесь — это, фактически, обнаружение конфликта изменений.
Ты что-то путаешь. Обычно deadlock это взаимоблокировка в результате ошибки имплементации. Скажем, классический пример — перевод денег с аккаунта A1 на аккаунт A2 при наивной имплементации возможен deadlock если аккаунты будут будут блокироваться в произвольном порядке — один пытается заблокировать A1, затем A2, а второй пытается A2, затем A1 — то они зависнут. Если же ввести отношение порядка и блокировать всегда A1,A2 — то дедлоков никаких не будет.
S>Его проявление в мире пессимистичных блокировок. S>Какой бы способ вы ни выбрали, у вас всё равно возможна ситуация "ой, между тем, как мы показали вам цену, и вашим нажатием на кнопку Save, произошли изменения. Будете повторять?".
Так это OL. А в PL будет просто "Не могу открыть Соглашение, т.к. кто-то сейчас проверяет Заказ связанный с этим Соглашением. Попробуйте позже." или просто песочные часики.
S>В pessimistic locking это будет как раз deadlock. В Optimistic locking это будет "расхождение таймстампов".
С OL может возникнуть livelock и starvation... что тоже неприятно.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Это классический race condition, который невозможно разрулить без предоставления однопоточного write-access ко всей модели данных. Это может быть сделано транзакциями уровня serializable, архитектурой LMAX, юизнестранзакциями с блокировкой "всего" и другими способами.
В случае же многопоточного доступа, мы можем играться вероятностями и временем задержки обновления цен в заказах, ничего более.
Здравствуйте, IB, Вы писали:
IB>Для этой проблемы другого решения нет.
Есть, ибо транзакции- это один из инструментов монопольного доступа к жанным. Выше уже упоминали LMAX — еще один инструмент.
Здравствуйте, Poul_Ko, Вы писали:
P_K>Либо перенести блокировки с базы на уровень выше — в бизнес-слой. Вот с целью ресёча такого решения я и затеял данную тему.
Вот это тот самый случай, когда лечение хуже болезни. Нормально реализовать транзакционность в бизнес слое — весьма нетривиальная задачка, смело умножайте прикидочные эстимейты на 10 и прибавьте 100% вероятность иметь невоспроизводимые баги месяцами.