Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  08:37[Войти] | [Зарегистрироваться]
Ответ на вопрос № 44157

31-07-2006 07:04
Доброго времени суток. Использую firebird 1.5 в качестве сервера БД. Проблема не новая, скорее даже не проблема. Вобщем суть: сервер держит базу склада, одновременно работают несколько человек и составляют заказы на метериалы, при сохранении заказа, назовем его "проводкой", необходимо временно заблокировать записи с материалами, которые мы запросили, провести списние и потом разрешить доступ. Думаю понятно, что это делается для того, чтобы корректно списывались остатки. Решил проблему так - есть встроенная процедура по списанию.
ньюанс -  в ней цикл, в котором пытаемся сделать апдейт подходящим материалам до тех пор пока апдейт не выполнится, затем "select ... for update with lock". Блокируем материалы под себя.
Затем проводим списание. Про цедура вызывается в транзации с параметрами: read_committed, rec_version, wait - благодаря чему она не вылетает с ошибкой Deadlock из цикла с апдейтом. Теперь суть вопроса: можно ли как-то избавится от цикла и блокировок? набор материалов может достигать 100-200 записей, к тому же на каждую запись на складе может подобраться еще от 1 до 100 подходящих. Получается что сперва каждую пытаемся проапдейтить, потом заблокировать и потом уже только изменять. При больших объемах приходиться ждать...

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

01-08-2006 07:46 | Сообщение от автора вопроса
Попробую реализовать последний вариант, в принципе, он похоже наиболее подходит, только надо реализовать ограничение по времени ожидания. Спасибо большое за помощь. Извините, если был через чур уверенным в своих знаниях Firebird.

01-08-2006 06:47
Добро пожаловать в увлекательный мир транзакций! :)

4. вопрос по снапшоту, он отслеживает версии? т.е если делать снапшот с Вашим примером, будет deadlock?
Конечно. DeadLock будет всегда, когда две транзакции (независимо от их уровня изоляции) пытаются изменить одну и ту же запись. Пожалуй, единственный случай, когда мы не получим DeadLock, это использование транзакции с параметрами read_committed, no_rec_version и wait. Вообще это довольно занятно, и, видимо, специально так сделано, поскольку, вероятно, после отпускания блокировки в этом случае сервер вновь перечитывает уже новую подтвержденную версию записи и пытается изменить ее. Что, очевидно, должно увенчаться успехом.

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

В таком варианте может подойти транзакция с параметрами write, consistency, wait. В этом случае транзакция будет выполняться так, как будто бы других просто не существует - она блокирует все - и чтение, и запись - для других до тех пор, пока сама не завершится. Потом после ее завершения другие выполнятся вслед за ней. Это так называемый сериализуемый образ, или SNAPSHOT TABLE STABILITY.

01-08-2006 06:04 | Сообщение от автора вопроса
наконец-то более менее поняли друг, друга..
1. абсолютно согласен, что в приведенном Вами примере будет deadock, я не понял до конца сперва...
2. сделанные блокировки как раз и не дают получить старую версию, и все работает, но сервак будет "изнасилован".
3. в принципе можно убрать блокировки, делать no_wait и вываливать юзеру сообщение, что-нить вроде попробуйте еще раз, или цикл с попыткой выполнить процедуру сделать на клиенте, но тогда при большом числе пользователей, каждый должен будет по нескольку раз "тыкать" кнопку, чтобы "вклиниться" между транзакциями или делать не клиент-сервер, а клиент-"очередь проводок"-сервер. как-то не хочется, честно говоря.
4. вопрос по снапшоту, он отслеживает версии? т.е если делать снапшот с Вашим примером, будет deadlock?
5. может есть какой-то другой более удобный вариант, чтобы и пользователя не напрягать и сервак не перегружать.
Грубо говоря принцип должен быть такой:
1.отправка документа "на проводку"
2.ожидание своей очереди, с ограниченным максимальным ожиданием.
3.обработка документа, списание материалов.
4.вывод результата пользователю о списанных материалах, либо об истечении времени ожидания.
Этот алгоритм реализован блокировками, но тяжелый для сервака. Может кто решал такую проблему?

01-08-2006 05:09
1. стартуя транзацию снапшот и работая в ней мы видим только данные, "закомиченные" на момент старта, находясь "внутри" мы не увидим изменения других транзакций.
Насколько я понял условие, нужно именно это. Или нет?

2. Deadlock не будет, транзакция Wait будет ждать, именно ждать, а не вылетать с deadlock.
Она будет ждать, и после завершения первой вылетит с DeadLock. Советую проверить.

первая транзакция нормально завершается. и 2 тоже. причем материала останется кол.-во, которое задано в последней выполненной транзакции. на основании чего транзакция 2 не должна завершаться?
А вот вторая вылетит с DeadLock. Поясню на пальцах. Может, и другим полезно будет. Подчеркиваю - речь идет об одной и той же записи.

1. Была запись с версией 1.
2. Транзакция №1 ее изменила, появилась запись с версией 2. При повторном чтении записи транзакция №1 увидит запись с версией 2.
3. Стартует транзакция №2, видит запись с версией 1.
4. Транзакция №2 изменяет запись, появилась запись версией 3.
5. Транзакция №1 подтверждает изменения. Подтвержденной становится версия 2 вместо версии 1.
6. Транзакция №2 подтверждает изменения. Сервер пытается сделать подтвержденной версию 3 вместо версии 1. Но вместо версии 1 подтвержденной стала версия 2. Поэтому сервер выдает DeadLock.

Если указан параметр no_wait, DeadLock выскочит сразу, а если wait, то только при завершении конкурирующей транзакции. Но выскочит в любом случае.

По поводу кода - посмотрел еще раз, - да, он будет работать. Но это будут действительно очень большие тормоза. Нельзя так сервер насиловать.

01-08-2006 04:38 | Сообщение от автора вопроса
1. стартуя транзацию снапшот и работая в ней мы видим только данные, "закомиченные" на момент старта, находясь "внутри" мы не увидим изменения других транзакций.
2. Deadlock не будет, транзакция Wait будет ждать, именно ждать, а не вылетать с deadlock. Элементарно проверить поставить "стопарь" в отладчике перед комитом и запустить сам экзешник, пока в дебагере не закомитим, экзешник будет висеть и ждать...
а вот если делать no_wait, то тогда как раз и вылетим в deadlock из-за того, что записи заблокированы, проверьте...
3. плохо описал пример, попробую еще раз, корректно:
есть 10 шт. стартуем транзакцию 1, увидели эти 10, сделали апдейт, изменили статус документа, добавили еще кое какие записи. Транзакия еще не завершена..
стартуем транзакцию 2, опять же увидели 10 шт, сделали апдэйт, и т.д.
после этого первая транзакция нормально завершается. и 2 тоже. причем материала останется кол.-во, которое задано в последней выполненной транзакции. на основании чего транзакция 2 не должна завершаться?

01-08-2006 04:18
Хозяин - барин, конечно...

1. не согласен в принципе в Вами. В вашем варианте обе транзации, выполнятся, и будет произведено списание
А вот зря не согласны - почитайте мануалы и статьи или просто проверьте... В Вашем примере при попытке подтверждения второй транзакции получим DeadLock (Транзакция read_committed rec_version wait). Очень рекомендую проверить.
снапшот - вобще не к месту, нам нужно в момент самого списания внутри процедуры видеть реальное кол.-во, а не на момент старта транзакции
И опять - почитайте мануалы и статьи или просто проверьте... - изменения, сделанные транзакцией SNAPSHOT (как в общем-то и любого уровня изоляции), видны в рамках самой транзакции.

01-08-2006 03:03 | Сообщение от автора вопроса
1. не согласен в принципе в Вами. В вашем варианте обе транзации, выполнятся, и будет произведено списание. пример:
было 10 шт. на складе. в первой транзакции проверили и сказали что забираем 8, транзакция еще не подтверждена, в это время вторая транзакция стартует и видит тоже 10 шт. и например забирает 5. в итоге обе транзации отработают и оба документа будут "проведены" - а это неправильно.
2. блокировки работают прекрасно, т.к. блокируют конкретные записи в базе на update почитайте мануалы и статьи или просто проверьте...
3. снапшот - вобще не к месту, нам нужно в момент самого списания внутри процедуры видеть реальное кол.-во, а не на момент старта транзакции.

01-08-2006 02:46
Начнем по порядку.

Во-первых, если 2 пользователя попытаются ОДНОВРЕМЕННО списать какой-то материал (или материалы), ВСЕГДА кому-то из них будет не судьба. Поэтому вопрос не в том, откуда взять им обоим материалы, которых нет, а в том, кто первый эту не судьбу получит.

Теперь что происходит в рамках транзакции. Пользователь №1 запускает транзакцию read_committed rec_version. Читает данные и проверяет на наличие материалов. Ок, пошел дальше - начинает списывать. В этот момент пользователь №2 запускает транзакцию read_committed rec_version, читает данные и видит, что материалы тоже есть в наличии (поскольку транзакция №1 свои данные не подтвердила). Ок, он тоже начинает списывать. И вот тут, кто первый свою транзакцию завершит, тот и изменит состояние базы данных. А второму будет не судьба. Неактуальных данных транзакции здесь прочитать не могут в принципе, если только не подтверждать ее после списания каждой записи (что в данном случае крайне нехорошо).

Пользователь №2 получил не судьбу. Ничего страшного, пусть еще раз запустит процесс списания и увидит, почему ему эту не судьбу нарисовали (если материалов уже нет), или благополучно завершит, если они есть в наличии.

Приведенный код блокировки не может работать в принципе, поскольку в нем используются локальные переменные, и для каждого пользователя будет запущена своя процедура со своими переменными. Т.е. блокирует он только самого себя. А надо ли? И работала эта процедура только потому, что работали транзакции.

Кстати, может есть смысл подумать об использовании транзакции SNAPSHOT?

01-08-2006 01:40 | Сообщение от автора вопроса
возможно я несколько не допонимаю правил работы с транзакциями...но!
прежде чем списывать материалы, мы должны проверить, есть ли подходящие, иначе не давать сделать проводку.
если делать без блокировок, то допустим мы проверили 100 позиций метериалов, и начинаем списывать с каждой разное кол.-во, в это время другой пользователь, может зайти и изменить кол.-во или тоже выполнить проводку своего заказа, естесствено в новой своей транзакции, по скольку записи не заблокированы, транзакции будут позволять работать и в каждой будет "видно" то кол.-во, которое было на момент старта транзакции, т.к. параметры read_commited, а пока процедура не отработала, транзакцию не можем подтвердить. получается что при большом объеме данные внутри процедуры будут неактуальные....
поэтому сделал такой цикл и блокировку внутри процедуры
keylocked=1;
while (keylocked=1) do
begin
  update materials set kolvo=kolvo where id_materials=:id_mat;
  if (sqlcode=0) then
    keylocked=0;
end
Select kolvo from materials where id_materials=:id_mat for update with lock;
т.к. процедура выполняется в транзакции wait, транзакция будет ждать пока подтвердиться или откатиться предыдущая и разблокирует записи, либо откатиться сама по истечению времени ожидания - выставляется у самого компонента в Delphi.
Такой принцип работает - проверенно. Но при больших объемах и большом числе пользователей приходится ждать, пока проверим есть материал, проверим на блокировку, заблокируем и потом только пристуим к списанию...

01-08-2006 01:18 | Вопрос к автору: запрос дополнительной информации
Не совсем понял логики.
при сохранении заказа, назовем его "проводкой", необходимо временно заблокировать записи с материалами, которые мы запросили, провести списние и потом разрешить доступ. Думаю понятно, что это делается для того, чтобы корректно списывались остатки
А зачем? Почему бы не сделать это в рамках одной транзакции?
сперва каждую пытаемся проапдейтить, потом заблокировать и потом уже только изменять
Это как?

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Два кольца, два конца, посередине гвоздик.
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования