Конференция "Базы" » Транзакции в ADO [D7, MSSQL]
 
  • Hiller (15.05.08 17:38) [0]
    Здравствуйте, коллеги!
    Раньше никогда не работал в АДО, а вот пришлось.
    Проблема такая, при старте транзакции пишет
    ---------------------------
    Debugger Exception Notification
    ---------------------------
    Project prjPersonal.exe raised exception class EOleException with message 'Не удается создать новую транзакцию из-за превышения допустимой емкости'. Process stopped. Use Step or Run to continue.
    ---------------------------
    OK   Help  
    ---------------------------

    Код, где это происходит следующий:

    ===
    dbMain: TADOConnection;
    quDBUpdate: TADOQuery;
    dmDatabase - форма с компонентами
    ===


    function DoSQL(aSQL: string): integer;
    begin
     dmDatabase.quDBUpdate.SQL.Text := aSQL;
     result := dmDatabase.quDBUpdate.ExecSQL;
    end;

    procedure DoDBUpdate(aNum: integer; aSQL: string);
    begin
     if dmDatabase.dbMain.Connected then   //Здесь все нормально,  
                                                           //соединение установлено
     dmDatabase.dbMain.BeginTrans; //Вот здесь падает, ага
     try
       if not WasUpdate(aNum) then
       begin
         DoSQL(aSql);
         DoSQL('INSERT INTO VERSION (VERSION_NUM, UPDATE_DATE) VALUES (' + IntToStr(aNum) + ', GETDATE())');
       end;
     except
       dmDatabase.dbMain.RollbackTrans;
       raise
     end;
     dmDatabase.dbMain.CommitTrans;
    end;


    Дельфя седьмая, БД MSSQL.
    Помогите, кто чем может :)
  • BoxTer (16.05.08 07:42) [1]
    ConnectionString какой?
  • Hiller (16.05.08 09:40) [2]
    Provider=SQLOLEDB.1;Password=personal;Persist Security Info=True;User ID=personal;Initial Catalog=KADR;Data Source=W1824

  • Hiller (16.05.08 09:46) [3]
    Извиняюсь, обманул :(
    'Provider=SQLOLEDB.1;Password=personal;Persist Security Info=True;User ID=PERSONAL;Initial Catalog=OKIPO;Data Source=W1824;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=W1824;Use Encryption for Data=False;Tag with column collation when possible=False'

  • BoxTer (16.05.08 10:04) [4]
    А IsolationLevel коннекшна?
  • Hiller (16.05.08 10:06) [5]
    ilReadCommitted
  • BoxTer (16.05.08 10:11) [6]
    Поставьте ilReadUnCommitted
  • BoxTer (16.05.08 10:17) [7]
    В вашем уровне изоляции(ilReadCommitted) перед началом новой транзакции имеет смысл добавить
    if not Connection.InTransaction
       then Connection.BeginTrans
       else Connection.CommitTrans;

  • Кщд (16.05.08 10:22) [8]
    >BoxTer   (16.05.08 10:17) [7]
    безусловно commit'ить открытую транзакцию - на мой взгляд, не самая лучшая рекомендация
  • BoxTer (16.05.08 10:26) [9]
    Канешна довести до ума нужно, главное смысл я передал :)
  • Ega23 © (16.05.08 10:28) [10]
    Там и в логике ещё ошибка. Если
    not dmDatabase.dbMain.Connected

    , то по-любому Commit будет делаться.
  • Hiller (16.05.08 10:42) [11]

    > BoxTer   (16.05.08 10:17) [7]
    >
    > В вашем уровне изоляции(ilReadCommitted) перед началом новой
    > транзакции имеет смысл добавить
    > if not Connection.InTransaction

    Там никогда не должно быть InTransaction


    > Ega23 ©   (16.05.08 10:28) [10]
    >
    > Там и в логике ещё ошибка. Если not dmDatabase.dbMain.Connected,
    >  то по-любому Commit будет делаться.

    Это тестовая строка, чтобы убедиться что соединение установлено. В этом месте оно должно быть всегда.

    Да, и еще - разве АДО не поддерживает вложенность транзакций?
  • Ega23 © (16.05.08 10:48) [12]

    > Это тестовая строка, чтобы убедиться что соединение установлено.
    >  В этом месте оно должно быть всегда.


    Только не в таком виде.

    if not dmDatabase.dbMain.Connected then Exit;



    Сейчас пересмотрел код, первый раз raise не заметил. Логической ошибки нет, но всё равно - лишние exception-ы. Зачем?
  • BoxTer (16.05.08 10:56) [13]

    > Там никогда не должно быть InTransaction

    Ну дык там нет, в другом месте будет :)
    Проблема решилась?
  • sniknik © (16.05.08 11:09) [14]
    > Логической ошибки нет
    есть.

    > if not WasUpdate(aNum) then
    допустим условие функции true...

    > Да, и еще - разве АДО не поддерживает вложенность транзакций?
    ADO счтиай вообще ничего не поддерживает... все делает сервер, а ADO просто передает ему команды. (ну, не все так просто конечно, но прими это за основу)
    именно поэтому не пользуюсь сам и не рекомендую другим пользоваться транзакциями от компонент (мало ли чего напередает), предпочитаю выполнять команды сам, явно.

    + транзакция в данном случае не нужна вообще, достаточно составить пакет из 2х команд, все одно они у тебя динамические и компилятся всегда заново, и mssql сам "обернет" этот пакет неявной транзакцией.
    т.е. убираешь все связанное с транзакциями и оставляешь
    DoSQL(aSql + #13#10'INSERT INTO VERSION (VERSION_NUM, UPDATE_DATE) VALUES (' + IntToStr(aNum) + ', GETDATE())');
    exception и ре-raise тоже тогда не нужны.
  • версия для печати (16.05.08 11:12) [15]

    > Да, и еще - разве АДО не поддерживает вложенность транзакций?


    а что это такое
  • sniknik © (16.05.08 11:18) [16]
    > function DoSQL(aSQL: string): integer;
    идиотский метод...

    уж если приспичило, то делаешь у конекта Execute(aSQL).

    строка в [2], более "правильная", в [3] это явно при открытом конекте, чего делать в дизигне не стоит (в смысле держать открытым, чтобы он сам открывался при запуске программы).
  • Hiller (16.05.08 11:57) [17]

    > BoxTer   (16.05.08 10:56) [13]
    >
    >
    > > Там никогда не должно быть InTransaction
    >
    > Ну дык там нет, в другом месте будет :)
    > Проблема решилась?

    Нет, все тоже самое :(


    >
    > + транзакция в данном случае не нужна вообще, достаточно
    > составить пакет из 2х команд, все одно они у тебя динамические
    > и компилятся всегда заново, и mssql сам "обернет" этот пакет
    > неявной транзакцией.
    > т.е. убираешь все связанное с транзакциями и оставляешь
    > DoSQL(aSql + #13#10'INSERT INTO VERSION (VERSION_NUM, UPDATE_DATE)
    > VALUES (' + IntToStr(aNum) + ', GETDATE())');
    > exception и ре-raise тоже тогда не нужны.

    Чувствуется профи, спасибо, попробую :)


    > > function DoSQL(aSQL: string): integer;
    > идиотский метод...
    >
    > уж если приспичило, то делаешь у конекта Execute(aSQL).

    С этим извини, не согласен. Всегда делаю функции-обертки. Даже если в настоящий момент такая функция состоит из одной строки и по сути бессмысленна, в будущем весьма вероятно расширение функциональности. Это кстати, не метод, а сервисная функция, предполагаю использовать ее и в других местах.

    >
    > строка в [2], более "правильная", в [3] это явно при открытом
    > конекте, чего делать в дизигне не стоит (в смысле держать
    > открытым, чтобы он сам открывался при запуске программы).
    >
    >

    А оно так и есть - строка в[2] это состояние в дезайнтайме, строка в [3] - в рунтайме в момент выполнения указаного кода. Извиняюсь за то, что невольно ввел в заблуждение.
  • sniknik © (16.05.08 12:35) [18]
    > С этим извини, не согласен. Всегда делаю функции-обертки.
    и закрываешь себе возможность нормальной работы с параметрами... либо начинаешь городить еще и их передачу в такую функцию, путаешься естественно, + заставляешь сервер постоянно перекомпилять запросы т.к. он динамические. и не дай Гейтс. попадет такая обертка в цикл, начинаются "вопли" какой тормозной этот ваш ADO и т.д.. другие проблемы.
    а их могло бы и не быть пиши ты правильно, пусть на 1 строчку в некоторых местах и больше.
    экономишь строчки, теряешь производительность.

    > в будущем весьма вероятно расширение функциональности.
    до стандартной, уже имеющейся у ADO компонент функциональности тебе ее и за год не довести... просто выработаешь у себя перманентную привычку "ездить на велосипеде собственного изготовления с треугольными колесам"

    p.s. это конечно домыслы, сугубое имхо так сказать, может ты и пишешь правильно там где надо, а это используешь только подходящих под него местах. но... много раз уже видел подобное, и всегда стиль "растягивается" на все, т.е. "если увидел чайку, то и море рядом...".
  • Hiller (16.05.08 13:20) [19]

    > и закрываешь себе возможность нормальной работы с параметрами.
    > .. либо начинаешь городить еще и их передачу в такую функцию,
    >  путаешься естественно, + заставляешь сервер постоянно перекомпилять
    > запросы т.к. он динамические. и не дай Гейтс. попадет такая
    > обертка в цикл, начинаются "вопли" какой тормозной этот
    > ваш ADO и т.д.. другие проблемы.
    > а их могло бы и не быть пиши ты правильно, пусть на 1 строчку
    > в некоторых местах и больше.
    > экономишь строчки, теряешь производительность.

    Погоди, я не понял. Ты имеешь ввиду, что лучше В ЭТОЙ ФУНКЦИИ использовать внешнюю текстовую константу с запросом вместо того чтобы переопределять свойство SQL у компоненты, так? Я тебя понял так, что нужно вместо сервисной функции везде делать явный вызов метода. И именно с этим был не согласен.


    > > в будущем весьма вероятно расширение функциональности.
    >
    > до стандартной, уже имеющейся у ADO компонент функциональности
    > тебе ее и за год не довести...

    А это видимо ты не понял :) Я не собираюсь изобретать велосипед и переписывать компонент. Я просто забиваю на будущее возможность добавить какие-либо действия перед/после выполнения запроса. Если это не сделать, потом надо будет найти в коде все места, где выполнялся запрос, а так достаточно внести изменения в сервисную функцию.
  • sniknik © (16.05.08 13:59) [20]
    > Погоди, я не понял. Ты имеешь ввиду, что лучше В ЭТОЙ ФУНКЦИИ использовать внешнюю текстовую константу с запросом вместо того чтобы переопределять
    > свойство SQL у компоненты, так? Я тебя понял так, что нужно вместо сервисной функции везде делать явный вызов метода. И именно с этим был не согласен.

    вот изза этой фигни
    > ' + IntToStr(aNum) + '
    запрос становиться динамическим и перекомпиляется сервером каждый раз перед выполнением,
    правильно статически прописать запрос, а меняемую часть сделать параметром. причем твоя функция прямо таки навязывает стиль с изменением запроса, вместо параметров (передается строка запроса).
    не показан способ формирования первого запроса
    > procedure DoDBUpdate(aNum: integer; aSQL: string);
    но могу "забиться" на то что там тот же стиль, с переменными сделанными частью запроса...
    вот это вот я и называю идиотским подходом. неважно с чем ты там несогласен.

    > Я не собираюсь изобретать велосипед и переписывать компонент.
    поздравляю, хоть и не хотел, но начал.

    > а так достаточно внести изменения в сервисную функцию.
    вот вот. привычка к своему велосипеду уже сказывается. вместо того чтобы изыскать методы при нормальной работе.
  • Hiller (16.05.08 15:19) [21]

    >
    > вот изза этой фигни
    > > ' + IntToStr(aNum) + '
    > запрос становиться динамическим и перекомпиляется сервером
    > каждый раз перед выполнением,
    > правильно статически прописать запрос, а меняемую часть
    > сделать параметром. причем твоя функция прямо таки навязывает
    > стиль с изменением запроса, вместо параметров (передается
    > строка запроса).
    > не показан способ формирования первого запроса
    > > procedure DoDBUpdate(aNum: integer; aSQL: string);
    > но могу "забиться" на то что там тот же стиль, с переменными
    > сделанными частью запроса...
    > вот это вот я и называю идиотским подходом. неважно с чем
    > ты там несогласен.

    Ага, дошло. Спасибо, буду думать.


    >
    > > Я не собираюсь изобретать велосипед и переписывать компонент.
    >
    > поздравляю, хоть и не хотел, но начал.


    И в чем это выражается?


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


    Что есть "методы при нормальной работе"?
    Писать одинаковый код в сотне мест, а затем для внесения изменений перелопачивать весь проект? Чувствую, все-таки я чего-то не понял :)
  • ANB (16.05.08 15:40) [22]

    > Писать одинаковый код в сотне мест, а затем для внесения
    > изменений перелопачивать весь проект? Чувствую, все-таки
    > я чего-то не понял :)

    Если выносишь какой то код в процедуру/метод, то надо вынести его так, чтобы было правильно. А правильно - работать с параметрами, а не генерить на кажный чих новый запрос.
 
Конференция "Базы" » Транзакции в ADO [D7, MSSQL]
Есть новые Нет новых   [134434   +29][b:0][p:0.002]