[FireBird] deadlock; update conflicts with concurrent update
От: sushko Россия  
Дата: 16.02.16 12:37
Оценка:
Есть база данных с наименованиями и количеством на складе товара. Клиент А открывает количество товара для изменения, его клиентское приложение блокирует это количество путем запуска запроса
UPDATE remainders SET id=id WHERE id=?

в транзакции с параметром NOWAIT.

После этого клиент Б пытается продать этот товар, его клиентское приложение уменьшает количество товара путем запроса
UPDATE remainders SET remainder=remainder-1 WHERE id=?

в транзакции БЕЗ параметра NOWAIT. Транзакция клиента Б подвисает в ожидании, когда транзакция клиента А освободит ресурс, и висит так долго (десятки секунд минимум). После этого клиент А завершает транзакцию COMMIT'ом, после чего клиент Б получает от FireBird ошибку "deadlock; update conflicts with concurrent update".

Вопрос: как с этим бороться? Хотелось бы, чтобы после COMMIT'а клиента А транзакция клиента Б все-таки завершилась успешно.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Отредактировано 16.02.2016 12:42 sushko . Предыдущая версия . Еще …
Отредактировано 16.02.2016 12:39 sushko . Предыдущая версия .
Re: [FireBird] deadlock; update conflicts with concurrent update
От: BlackEric http://black-eric.lj.ru
Дата: 16.02.16 14:14
Оценка:
Здравствуйте, sushko, Вы писали:

S>Вопрос: как с этим бороться? Хотелось бы, чтобы после COMMIT'а клиента А транзакция клиента Б все-таки завершилась успешно.


Использовать короткие транзакции. Т.е. прочитали значение — закрыли.
Захотели редактировать — открыли, отредактировали, закрыли.
https://github.com/BlackEric001
Re[2]: [FireBird] deadlock; update conflicts with concurrent update
От: sushko Россия  
Дата: 17.02.16 07:17
Оценка:
Здравствуйте, BlackEric, Вы писали:

S>>Вопрос: как с этим бороться? Хотелось бы, чтобы после COMMIT'а клиента А транзакция клиента Б все-таки завершилась успешно.


BE>Использовать короткие транзакции. Т.е. прочитали значение — закрыли.

BE>Захотели редактировать — открыли, отредактировали, закрыли.

Так не бывает. Если пользователь A открыл товар для редактирования, надо сделать как-то так, чтобы пользователь B не смог его открыть для редактирования, т.к. заблокировать запись в транзакции. А если после этого A пойдет пить кофе, не закрыв окно редактирования товара, то транзакция короткой не получится.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Re[3]: [FireBird] deadlock; update conflicts with concurrent update
От: LuciferNovoros Россия  
Дата: 17.02.16 08:45
Оценка:
Здравствуйте, sushko, Вы писали:

S>Так не бывает. Если пользователь A открыл товар для редактирования, надо сделать как-то так, чтобы пользователь B не смог его открыть для редактирования, т.к. заблокировать запись в транзакции. А если после этого A пойдет пить кофе, не закрыв окно редактирования товара, то транзакция короткой не получится.


FB — версионник. И клиент В всегда получит некую версию записи, с которой будет работать. Другой вопрос, что запись может измениться, породив новую версию. И тогда клиент В получит отлуп. Если тебяч такое поведение не устраивает, то выставляй некий признак, что запись заблокирована другим пользователем. И давай отлуп клиенту сразу.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[4]: [FireBird] deadlock; update conflicts with concurrent
От: sushko Россия  
Дата: 17.02.16 09:33
Оценка:
Здравствуйте, LuciferNovoros, Вы писали:

S>>Так не бывает. Если пользователь A открыл товар для редактирования, надо сделать как-то так, чтобы пользователь B не смог его открыть для редактирования, т.к. заблокировать запись в транзакции. А если после этого A пойдет пить кофе, не закрыв окно редактирования товара, то транзакция короткой не получится.


LN>FB — версионник. И клиент В всегда получит некую версию записи, с которой будет работать.


Нет, не получит, т.к. клиент B хочет изменить эту запись, а не просто ее прочитать. Блокировка, кот. поставил А, не даст ему ее менять, и это правильно.

LN>Другой вопрос, что запись может измениться, породив новую версию. И тогда клиент В получит отлуп. Если тебяч такое поведение не устраивает, то выставляй некий признак, что запись заблокирована другим пользователем. И давай отлуп клиенту сразу.


Не получится, т.к. если этот признак выставлять и потом снимать в рамках транзакции клиента А, то клиент В не увидит этого признака, т.к. транзакция клиента А на момент начала транзакции клиента В не завершилась. Если же этот признак выставлять до начала транзакции клиента А (напр. отдельной транзакцией от имени А), то есть вероятность того, что посреди "главной" транзакции клиента А рубанется электричество и признак останется установленным навсегда.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Отредактировано 17.02.2016 9:33 sushko . Предыдущая версия .
Re[4]: [FireBird] deadlock; update conflicts with concurrent
От: sushko Россия  
Дата: 17.02.16 09:37
Оценка:
Здравствуйте, LuciferNovoros, Вы писали:

LN>FB — версионник. И клиент В всегда получит некую версию записи, с которой будет работать. Другой вопрос, что запись может измениться, породив новую версию. И тогда клиент В получит отлуп. Если тебяч такое поведение не устраивает, то выставляй некий признак, что запись заблокирована другим пользователем. И давай отлуп клиенту сразу.


Вообще, я не понимаю, о чем мы спорим. А заблокировал запись, В пытается ее изменить в WAIT-транзакции, и эта транзакция В подвисает до тех пор, пока не закончится транзакция А, и это правильно. Но почему-то по завершении транзакции А транзакция В не начинает работать, как можно было бы предположить по смыслу слова WAIT, а завершается с ошибкой. В чем тогда смысл параметра WAIT у транзакции В?
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Отредактировано 17.02.2016 9:38 sushko . Предыдущая версия .
Re[5]: [FireBird] deadlock; update conflicts with concurrent
От: LuciferNovoros Россия  
Дата: 17.02.16 09:48
Оценка:
Здравствуйте, sushko, Вы писали:

S>Вообще, я не понимаю, о чем мы спорим. А заблокировал запись, В пытается ее изменить в WAIT-транзакции, и эта транзакция В подвисает до тех пор, пока не закончится транзакция А, и это правильно. Но почему-то по завершении транзакции А транзакция В не начинает работать, как можно было бы предположить по смыслу слова WAIT, а завершается с ошибкой. В чем тогда смысл параметра WAIT у транзакции В?


Ты про это?

WAIT / NO WAIT (константы wait и nowait) — Режимы обработки конфликтов блокировок. Если транзакция стартует в режиме WAIT (по умолчанию), и при выполнении операции (как правило, изменения данных, за исключением режима no_rec_version) обнаруживается конфликт, то операция "замораживается" до разрешения конфликта. В режиме NO WAIT сообщение о конфликте выдается приложению немедленно (возникает ошибка), а операция, которая привела к конфликту, отменяется. В случае взаимоблокировки двух wait-транзакций сервер автоматически обнаруживает эту ситуацию, и разблокирует одну из транзакций (как будто она стартовала как nowait) через интервал времени, определенный в IBCONFIG параметром DEADLOCK_TIMEOUT, который по умолчанию равен 10 секундам.


Тогда — короткие транзакции. Пусть себе клиент А сколь угодно пьет кофе и курит в курилке. Но реальные изменения происходить будут, как только он нажмет кнопку. То есть, ты вычитываешь для него количество товара, он его изменил и пошел курить. Клиент В в этот момент пусть себе продает — запись ведь не заблокирована! И как только клиент А нажимает кнопку, — стартует транзакция, подтверждающая его изменения.

З.Ы. А вообще я бы делал не так. Приход — одна таблица, расход — другая. А итоговая цифра просто результат вычислений по этим таблицам.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: [FireBird] deadlock; update conflicts with concurrent update
От: BlackEric http://black-eric.lj.ru
Дата: 17.02.16 09:53
Оценка:
Здравствуйте, sushko, Вы писали:

S>Здравствуйте, BlackEric, Вы писали:


S>>>Вопрос: как с этим бороться? Хотелось бы, чтобы после COMMIT'а клиента А транзакция клиента Б все-таки завершилась успешно.


BE>>Использовать короткие транзакции. Т.е. прочитали значение — закрыли.

BE>>Захотели редактировать — открыли, отредактировали, закрыли.

S>Так не бывает. Если пользователь A открыл товар для редактирования, надо сделать как-то так, чтобы пользователь B не смог его открыть для редактирования, т.к. заблокировать запись в транзакции. А если после этого A пойдет пить кофе, не закрыв окно редактирования товара, то транзакция короткой не получится.


Прочитал — транзакцию закрыл. Ничего не заблокировано.
Потом при нажатии кнопки сохранить после редактирования запись блокируется при старте транзакции.
Проверяется не была ли изменена запись.
Если не изменена, то update and commit.
Если изменена, то rollback.
Транзакция завершена, ничего не заблокировано.

Это короткие транзакции, вероятность блокировки минимальна.
https://github.com/BlackEric001
Re[5]: [FireBird] deadlock; update conflicts with concurrent
От: LuciferNovoros Россия  
Дата: 17.02.16 09:58
Оценка:
Здравствуйте, sushko, Вы писали:

S>то есть вероятность того, что посреди "главной" транзакции клиента А рубанется электричество и признак останется установленным навсегда.


Вырвать навсегда руки сисадмину и обеспечить сервер БД бесперебойником.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[6]: [FireBird] deadlock; update conflicts with concurrent
От: sushko Россия  
Дата: 17.02.16 10:21
Оценка:
Здравствуйте, LuciferNovoros, Вы писали:

S>>то есть вероятность того, что посреди "главной" транзакции клиента А рубанется электричество и признак останется установленным навсегда.

LN>Вырвать навсегда руки сисадмину и обеспечить сервер БД бесперебойником.

Не поможет: электричество-то рубанулось на клиенте.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Re[6]: [FireBird] deadlock; update conflicts with concurrent
От: sushko Россия  
Дата: 17.02.16 10:30
Оценка:
Здравствуйте, LuciferNovoros, Вы писали:

LN>Здравствуйте, sushko, Вы писали:


LN>Ты про это?


Да, про это

LN>Тогда — короткие транзакции. Пусть себе клиент А сколь угодно пьет кофе и курит в курилке. Но реальные изменения происходить будут, как только он нажмет кнопку. То есть, ты вычитываешь для него количество товара, он его изменил и пошел курить. Клиент В в этот момент пусть себе продает — запись ведь не заблокирована! И как только клиент А нажимает кнопку, — стартует транзакция, подтверждающая его изменения.


Ничего не получится:

— В момент времени X программа считает, что на складе 10 единиц товара, и об этом знают клиенты А и Б
— В момент X+1 пользователь А пересчитывает к-во товара на полках и обнаруживает, что реально товара там только 8 штук. Пользователь А открывает диалоговое окно в климентском приложении для того, чтобы изменить к-во на реальное, и ставит в окошке ввода число 8, но OK не нажимает
— В момент X+2 пользователь B делает продажу и т.о. уменьшает остаток на единицу
UPDATE remainders SET remainder=remainder-1 WHERE id=?

— В момент X+3 пользователь А нажимает OK и т.о. запускает в базу запрос
UPDATE remainders SET remainder=8 WHERE id=?


В результате мы будет иметь в БД остаток, равный 8, хотя по факту товара осталось 7 штук.

LN>З.Ы. А вообще я бы делал не так. Приход — одна таблица, расход — другая. А итоговая цифра просто результат вычислений по этим таблицам.


Не получится, т.к. это система для малого бизнеса, например, маленький продуктовый магазинчик в подвале соседнего с Вами дома. Т.е. транзакций очень много, сотни чеков в день (т.е. считать долго), а железо слабое (низкая рентабельность предприятия не позволяет тратиться на IT).
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Отредактировано 17.02.2016 10:30 sushko . Предыдущая версия .
Re[4]: [FireBird] deadlock; update conflicts with concurrent update
От: sushko Россия  
Дата: 17.02.16 10:37
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Прочитал — транзакцию закрыл. Ничего не заблокировано.

BE>Потом при нажатии кнопки сохранить после редактирования запись блокируется при старте транзакции.
BE>Проверяется не была ли изменена запись.
BE>Если не изменена, то update and commit.
BE>Если изменена, то rollback.
BE>Транзакция завершена, ничего не заблокировано.

Тогда полная фигня получится:

— Пользователь C открывает на клиенте C окно для изменения записи о товаре
— Пользователь D открывает на клиенте D окно для изменения записи о товаре
— Пользователь C делает большую работу в открывшемся окне. Ну, например, работу длиной в полчаса
— Пользователь D нажимает кнопку OK
— Пользователь C нажимает кнопку OK. Программа видит, что запись была изменена, и делает rollback, выкинув т.о. полчаса работы человека
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Re[5]: [FireBird] deadlock; update conflicts with concurrent update
От: BlackEric http://black-eric.lj.ru
Дата: 17.02.16 10:38
Оценка:
Здравствуйте, sushko, Вы писали:

S>Тогда полная фигня получится:


S>- Пользователь C открывает на клиенте C окно для изменения записи о товаре

S>- Пользователь D открывает на клиенте D окно для изменения записи о товаре
S>- Пользователь C делает большую работу в открывшемся окне. Ну, например, работу длиной в полчаса
S>- Пользователь D нажимает кнопку OK
S>- Пользователь C нажимает кнопку OK. Программа видит, что запись была изменена, и делает rollback, выкинув т.о. полчаса работы человека

Тогда блокируйте запись для изменения. 3-го не дано.
https://github.com/BlackEric001
Re: [FireBird] deadlock; update conflicts with concurrent up
От: sushko Россия  
Дата: 17.02.16 10:42
Оценка:
Дополню свой собственный пост. Попробовал вместо следующего запроса, исполняемого ради блокировки записи:
UPDATE remainders SET id=id WHERE id=?


выполнить другие запросы (с фетчем записей):
SELECT * FROM remainders WHERE id=? FOR UPDATE
SELECT * FROM remainders WHERE id=? WITH LOCK
SELECT * FROM remainders WHERE id=? FOR UPDATE WITH LOCK


По факту, если присутствует WITH LOCK, то в результате получается та же фигня, что и с просто запросом на UPDATE (см. выше); если WITH LOCK отсутствует, то запись просто не блокируется, т.е. FOR UPDATE тупо не работает.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Отредактировано 17.02.2016 10:43 sushko . Предыдущая версия .
Re[6]: [FireBird] deadlock; update conflicts with concurrent update
От: sushko Россия  
Дата: 17.02.16 10:45
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Тогда блокируйте запись для изменения. 3-го не дано.


Я и блокирую, но блокировка работает страшно некорретно. Прочитайте, пожалуйста, мое исходное сообщение в этом треде.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Re[7]: [FireBird] deadlock; update conflicts with concurrent update
От: BlackEric http://black-eric.lj.ru
Дата: 17.02.16 10:46
Оценка:
Здравствуйте, sushko, Вы писали:

S>Я и блокирую, но блокировка работает страшно некорретно. Прочитайте, пожалуйста, мое исходное сообщение в этом треде.

Все там корректно. Что вас не устраивает? Что вы хотите получить?
https://github.com/BlackEric001
Re[8]: [FireBird] deadlock; update conflicts with concurrent update
От: sushko Россия  
Дата: 17.02.16 11:05
Оценка:
Здравствуйте, BlackEric, Вы писали:

S>>Я и блокирую, но блокировка работает страшно некорретно. Прочитайте, пожалуйста, мое исходное сообщение в этом треде.

BE>Все там корректно. Что вас не устраивает? Что вы хотите получить?

Рррр. Прочитайте, пожалуйста, первое сообщение в этом треде, там все написано.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Re[9]: [FireBird] deadlock; update conflicts with concurrent update
От: BlackEric http://black-eric.lj.ru
Дата: 17.02.16 11:13
Оценка:
Здравствуйте, sushko, Вы писали:

S>Здравствуйте, BlackEric, Вы писали:


S>>>Я и блокирую, но блокировка работает страшно некорретно. Прочитайте, пожалуйста, мое исходное сообщение в этом треде.

BE>>Все там корректно. Что вас не устраивает? Что вы хотите получить?

S>Рррр. Прочитайте, пожалуйста, первое сообщение в этом треде, там все написано.


Я его прочитал.
А если после всех модификаций получится отрицательное число?

ну обрабатывайте deadlock, не показывая юзеру и рестартуйте транзакцию.
https://github.com/BlackEric001
Re[2]: [FireBird] deadlock; update conflicts with concurrent up
От: LuciferNovoros Россия  
Дата: 17.02.16 13:00
Оценка: -1
Здравствуйте, sushko, Вы писали:

S>По факту, если присутствует WITH LOCK, то в результате получается та же фигня, что и с просто запросом на UPDATE (см. выше); если WITH LOCK отсутствует, то запись просто не блокируется, т.е. FOR UPDATE тупо не работает.


Потому что не надо делать. От слова совсем. Надо сделать таблицы прихода и таблицы расхода товаров. Как я тебе уже и написал. И таблицу остатков, куда все это будет сводиться. Иначе у тебя получится полная хрень, когда несколько пользователей ломанутся обновлять одно и то же поле, которое в принципе не должно быть обновляемым напрямую, потому что оно должно быть вычисляемым.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[10]: [FireBird] deadlock; update conflicts with concurrent update
От: sushko Россия  
Дата: 17.02.16 13:52
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>А если после всех модификаций получится отрицательное число?


Это вопрос по бизнес-логике приложения, мы ее сейчас не рассматриваем: мой вопрос касается только технической реализации транзакций в FB.

BE>ну обрабатывайте deadlock, не показывая юзеру и рестартуйте транзакцию.


Вы упорно не хотите понять мой вопрос. Я спрашиваю: В чем смысл параметра WAIT, если что с ним, что без него я получаю отлуп?

Я ожидал, что с WAIT транзакция клиента B из исходного сообщения выполнится после того, как клиент А снимет блокировку, а с параметром NOWAIT клиент B получит отлуп при попытке изменить заблокированную запись. В реальности же клиент B получает отлуп всегда, что с WAIT, что с NOWAIT. В чем тогда смысл этого параметра?
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.