Помогите разобраться с транзакциями!

IBX, FIBPlus, UIB, ADO, .Net и прочее-прочее-прочее, в общем все, что относится к созданию приложений, работающих с InterBase, Firebird и Yaffil - клиент-серверных, трехзвенных, консольных и т.п.

Модератор: kdv

Ответить
Zoran
Сообщения: 37
Зарегистрирован: 27 авг 2008, 12:08

Помогите разобраться с транзакциями!

Сообщение Zoran » 16 июл 2009, 15:57

Подскажите, сервер с нескольких потоков коннектится к БД. (это просто к сведению. может и несколько серверов коннектится к 1 БД )
(написано на Delphi 7, БД на FireBird 1.55 и 2.1)

в рамках каждого потока создается DataModule, на котором лежат IBDataBase, IBSQL и т.д.
на форме есть компонент IBTransaction, установлены параметрыAllowAutoStart=true, Params:
read_committed
rec_version
nowait

Перед каждым выполнением запроса вызывается процедура _StartTransaction, после вызывается _Commit или _RollBack

Код: Выделить всё

procedure TDirectIBConnection._StartTransaction;
begin
  Inc(FTransCount);
  if FTransCount = 1 then
    ForceStartTransaction;
end;

procedure TDirectIBConnection.ForceStartTransaction;
begin
  _CheckConnected;
  if not ibtrMain.InTransaction then
    ibtrMain.StartTransaction;
end;

//где ibtrMain - имя компонента IBTransaction 

procedure TDirectIBConnection._Commit;
begin
  if FTransCount > 0 then
    Dec(FTransCount);
  if (FTransCount = 0) then
    ForceCommit;
end;

procedure TDirectIBConnection.ForceCommit;
begin
  if ibtrMain.InTransaction then
    ibtrMain.Commit;
  FTransCount := 0;
end;

procedure TDirectIBConnection._Rollback;
begin
  ForceRollback;
end;

procedure TDirectIBConnection.ForceRollback;
begin
  if ibtrMain.InTransaction then
    ibtrMain.Rollback;
  FTransCount := 0;
end;
Дополнительно при старте транзакции в БД в спец. таблицу пишется информация о том, что стартована транзакция и от какого пользователя, а при завершении транзакции эта информация удаляется.

Вроде все логично. Но периодически возникает ситуация когда пользователь вводит записи и сам видит, что они введены, но другие пользователи их не видят. После перезапуска системы и этот пользователь записи уже не видит.

Теоретически понятно, что произошло рассогласование количества вызовов _StartTransaction / _Commit и не было вызово _RollBack, которые бы все привели в норму. Но в коде такого куска найти не удалось :(.

Ситуация возникает раз в неделю при одновременной работе более чем 100 пользователей и смоделировать ее не удается. Логи сделать и просмотреть тоже нереально.

Соответственно вопрос, как мне обойти эту проблему? Может настройки транзакции поставить другие?
Думаю сделать чтение данные через другую транзакцию и тогда если транзакция добавления "зависла", тогда пользователь не увидит введенную запись сразу и можно будет тупо перезайти в систему. Криво, но других идей нет.

Посоветуйте!!!

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Помогите разобраться с транзакциями!

Сообщение kdv » 16 июл 2009, 23:21

идея контролировать кол-во стартованных в приложении транзакций порочна.
Но периодически возникает ситуация когда пользователь вводит записи и сам видит, что они введены, но другие пользователи их не видят.
значит транзакция пользователя не завершена. где то Вы в коде продрушляли commit. Так что точите управление транзакциями.

Zoran
Сообщения: 37
Зарегистрирован: 27 авг 2008, 12:08

Re: Помогите разобраться с транзакциями!

Сообщение Zoran » 17 июл 2009, 10:23

kdv писал(а):идея контролировать кол-во стартованных в приложении транзакций порочна.
...
значит транзакция пользователя не завершена. где то Вы в коде продрушляли commit. Так что точите управление транзакциями.
Дело в том, что на клиенте тоже можно писать скрипты на JScript и вызывать функции обращения к БД. Соответсвенно часто надо выполнить несколько запросов к БД в рамках 1 транзакции. Вот и сделан такой финт. Пользователь сам стартует транзакцию, вызвав соответсвующий метод, а далее сервер еще раз пытается стартовать транзакцию для каждого из выполняемых запросов. Соответственно счетчик нужен для отслеживания стартована транзакция или нет.

Если добавить к этому еще, что я не имею доступа к пользовательским базам, а только к своей тестовой, плюс из одного скрипта можно вызывать другой, тогда и получается, что выверить код я просто не могу. Нужно придумать какой то механизм автоматической защиты.

Была идея сделать отдельную кнопку Коммита, или коммитить автоматом, если машина пользователя простаивает более несколькихз минут, но это тоже фигня какая-то.

Вот я и ищу идеи на форуме, может кто подскажет мысль или хотябы направление, куда думать :)

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Помогите разобраться с транзакциями!

Сообщение kdv » 17 июл 2009, 14:04

Пользователь сам стартует транзакцию, вызвав соответствующий метод, а далее сервер еще раз пытается стартовать транзакцию для каждого из выполняемых запросов.
не понял смысла. если такая транзакция стартует для чтения, то можно ей сделать параметры read read committed, и пусть тогда такая транзакция висит вечно. Если же эта долгая транзакция на чтение и запись, то тогда ешьте кактус дальше.

сам по себе старт транзакции без выполняемого дальше sql оператора бессмысленен. Поэтому вместо настоящего старта транзакции в "соответствующем методе" можно просто запомнить параметры транзакции, с которыми должна стартовать транзакция при ближайшем выполнении SQL.

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

Zoran
Сообщения: 37
Зарегистрирован: 27 авг 2008, 12:08

Re: Помогите разобраться с транзакциями!

Сообщение Zoran » 17 июл 2009, 17:34

kdv писал(а):не понял смысла. если такая транзакция стартует для чтения, то можно ей сделать параметры read read committed, и пусть тогда такая транзакция висит вечно. Если же эта долгая транзакция на чтение и запись, то тогда ешьте кактус дальше.
нет, не так. Пользователь имеет возможность через реализованный интерфейс использовать функции StartTransaction, SQLOpen, SQLExec, SQLCommit и т.п. Далее он может написать программу на JScript в интерфейсе системы:
StartTransaction
resdataSet := SQLOpen(....)
SQLExec(insert...)
SQLExec(insert...)
SQLExec(insert...)
SQLExec(insert...)
...Тут кучу чего еще включая вызов диалоговых окон для ввода дополнительных параметров и т.п.
SQLCommit

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

далее алгоритм выполнения такой:
при вызове метода StartTransaction, на сервере стартует транзакция и счетчик количества транзакций увеличиывается на 1.
при выполнении команд SQLExec сервер опять пытается стартовать транзакцию перед выполнением запроса, но т.к. счетчик там уже 1 (значит транзакция стартована) он ее не стартует и выполняет запрос в рамках текущей транзакции увеличивая количество вызовов транзакции на 1. После завершения выполнения команды на сервере счетчик уменьшается на 1.
В итоге когда в скрипте пользователя вызывается SQLCommit - транзакция завершается.

Учитывая, что при каждом вызове SQLExec(insert...) идет обращение на сервер, оно может выполняться по медленному соединению и т.п., транзакция получается долгой и без диалоговых форм. Но в любом случае без этого никак, т.к. запросы должны выполнится в рамках 1 транзакции.

Счетчик на строне сервера нужен для того, чтобы если пользователь вызовет просто метод SQLExec(insert...), тогда транзакция стартует автоматом, если пользователю не надо выполнять несколько вызовов в рамках 1 транзакции.

Вот пришла идея: может отслеживать длительность транзакции и при превышении определенного времени закрывать ее автоматически с уведомлением пользователя. Т.е. на сервере при старте транзакции запоминать время старта и потом если превышен интервал автоматом закрывать транзакцию откатом с отсылкой на клиента соответствующего сообщения.

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

Есть еще какие либо варианты? Надеюсь алгоритм работы я описал понятно, если есть какие вопросы - пишите. Постараюсь ответить. Возможно объясняя алгоритм работы придумаю и решение :)

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Re: Помогите разобраться с транзакциями!

Сообщение Attid » 17 июл 2009, 18:15

не стартуй автоматом транзакцию, пусть пользователь явно управляет. если забыл сделать старт то пусть получит ошибку.

и еще сделать автоматическое закрытие транзакции по выполнению скрипта. в настройках по умолчанию откат транзакции, если забыл закомитеть, то ССЗБ.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Помогите разобраться с транзакциями!

Сообщение kdv » 17 июл 2009, 20:42

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

Zoran
Сообщения: 37
Зарегистрирован: 27 авг 2008, 12:08

Re: Помогите разобраться с транзакциями!

Сообщение Zoran » 22 июл 2009, 13:52

kdv писал(а):Вы, кажется, меня совсем не слушаете, потому что продолжаете напирать на "как у меня реализовано", "алгоритм" и т.д.
Я пытаюсь найти решение проблемы, а вы мне постоянно пишете, что "сам дурак". Я прекрасно понимаю, что сделано криво, но на данный момент переписать все полностью я не могу, да и не представляю как. Я пытаюсь найти решение конкретной проблемы: отловить и обработать ошибку незакрытой транзакции.
kdv писал(а):вопрос - насколько долгой?
а про "с диалоговыми формами" я уже привел пример про постоянно кипящий чайник.
Про чайник и я могу привести пример. У нас в офисе чайник включен постоянно, кто подошел, сразу налил горячей воды. И выключается он сам только когда кончится вода. Но эта история ни на шаг не приближает меня к решению проблемы.
Насколько долгой? - пусть будет 7 минут.
kdv писал(а):бррр... конечно, если транзакция с модификацией не завершена, то увидеть изменения можно только в этой самой транзакции, и ни в какой другой.
Так я тоже самое написал. Нового в вашем комментарии только "бррр..." У меня был вопрос применимо ли такое решение на практике и Могут ли быть побочные проблемы?
kdv писал(а):нет у вас никакого алгоритма. Вы даете в руки пользователю гранату по управлению транзакциями, и соответственно получаете результат.
А что делать, если такова поставленная задача (Пользователь должен иметь возможность писать подпрограммы внутри системы с использованием SQL команд.) Мне понятно, что надо свести все к коротким транзакциям, но не понятно как. Нужна идея о простейшей защите от "дурака" если пользователь "забыл" закрыть транзакцию.

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

Re: Помогите разобраться с транзакциями!

Сообщение Tonal » 22 июл 2009, 14:16

Мне как-то пришлось разбиратся с подобными проблемами в одном проекте.
На каждой форме было по 2-5 компонентов транзакций с автостартом... Правда скрипта не было. :)
Несколько идей и рефакторинго помогли. :)
Идеи такие:
1. Свёл число компонент до 3: читающая, пишущая, служебная (отдельный лог событий) .
2. Пишущая стартует только явно и явно же комитится в той же процедуре.
3. Пишущая как можно более короткая. Если нужно запрашивать что-то от пользователя, то сначала запрашивается (показываем диалог...) а потом, когда пользователь всё ввёл стартуем транзакцию и пишем в базу.

Для скриптов можно предложить следующий вариант:
1. Транзакция стартует автоматом, как только идёт обращение к базе из скрипта и транзакция не активна.
2. В скрипте нужно явно вызывать commit. После чего транзакция не активна.
3. По окончанию выполнения транзакция откатывается, если ещё активна.
4. Перед вызовом диалога из скрипта транзакция откатывается, если активна.

П.С. На самом деле был написан небольшой пакетик в стиле шаблона команда, который позволял вообще не использовать явный старт/стоп пишущей транзакции в приложении. :)

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Помогите разобраться с транзакциями!

Сообщение kdv » 23 июл 2009, 00:35

А что делать, если такова поставленная задача (Пользователь должен иметь возможность писать подпрограммы внутри системы с использованием SQL команд.)
вот интересно, Вы сами себе такую задачу придумали, или кто-то постановку такую сделал?
В любом случае, зачем Вы тогда вообще что-то пишете - дайте пользователю Дельфи, Вижуал Бейсик, и т.п. - пусть себе программы сам рисует.
Я пытаюсь найти решение проблемы, а вы мне постоянно пишете, что "сам дурак". Я прекрасно понимаю, что сделано криво, но на данный момент переписать все полностью я не могу, да и не представляю как. Я пытаюсь найти решение конкретной проблемы: отловить и обработать ошибку незакрытой транзакции.
здесь есть только два варианта.
1. вы даете пользователю все как есть, со стартами транзакций и т.п., и если он транзакцию не завершил, то сам дурак
2. вы своем интерфейсе всего-лишь симулируете старт транзакций, а обрабатываете их старт самостоятельно, в тот момент, когда нужно. Про это я уже писал.
Так я тоже самое написал. Нового в вашем комментарии только "бррр..." У меня был вопрос применимо ли такое решение на практике и Могут ли быть побочные проблемы?
Вы ее уже имеете, эту проблему. Насчет "решения" я не понял, о каком решении речь. Такое впечатление, что не имея опыта управления транзакциями в своем приложении, Вы пытаетесь решить "проблему" управления транзакциями для скриптового языка. Ну так читайте про транзакции здесь, например: www.ibase.ru/devinfo/ibx.htm Там треть статьи про это.
Но там про написание своего кода. Как Вы собираетесь учить управлять транзакциями пользователя? Зачем Вы вообще это ему в руки даете?

Ответить