-
Здравствуйте, коллеги! Раньше никогда не работал в АДО, а вот пришлось. Проблема такая, при старте транзакции пишет --------------------------- 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. Помогите, кто чем может :)
-
ConnectionString какой?
-
Provider=SQLOLEDB.1;Password=personal;Persist Security Info=True;User ID=personal;Initial Catalog=KADR;Data Source=W1824
-
Извиняюсь, обманул :( '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'
-
А IsolationLevel коннекшна?
-
ilReadCommitted
-
Поставьте ilReadUnCommitted
-
В вашем уровне изоляции(ilReadCommitted) перед началом новой транзакции имеет смысл добавить if not Connection.InTransaction
then Connection.BeginTrans
else Connection.CommitTrans;
-
>BoxTer (16.05.08 10:17) [7] безусловно commit'ить открытую транзакцию - на мой взгляд, не самая лучшая рекомендация
-
Канешна довести до ума нужно, главное смысл я передал :)
-
Там и в логике ещё ошибка. Если not dmDatabase.dbMain.Connected , то по-любому Commit будет делаться.
-
> 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 будет делаться.
Это тестовая строка, чтобы убедиться что соединение установлено. В этом месте оно должно быть всегда.
Да, и еще - разве АДО не поддерживает вложенность транзакций?
-
> Это тестовая строка, чтобы убедиться что соединение установлено. > В этом месте оно должно быть всегда.
Только не в таком виде. if not dmDatabase.dbMain.Connected then Exit; Сейчас пересмотрел код, первый раз raise не заметил. Логической ошибки нет, но всё равно - лишние exception-ы. Зачем?
-
> Там никогда не должно быть InTransaction
Ну дык там нет, в другом месте будет :) Проблема решилась?
-
> Логической ошибки нет есть.
> 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 тоже тогда не нужны.
-
> Да, и еще - разве АДО не поддерживает вложенность транзакций?
а что это такое
-
> function DoSQL(aSQL: string): integer; идиотский метод...
уж если приспичило, то делаешь у конекта Execute(aSQL).
строка в [2], более "правильная", в [3] это явно при открытом конекте, чего делать в дизигне не стоит (в смысле держать открытым, чтобы он сам открывался при запуске программы).
-
> 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] - в рунтайме в момент выполнения указаного кода. Извиняюсь за то, что невольно ввел в заблуждение.
-
> С этим извини, не согласен. Всегда делаю функции-обертки. и закрываешь себе возможность нормальной работы с параметрами... либо начинаешь городить еще и их передачу в такую функцию, путаешься естественно, + заставляешь сервер постоянно перекомпилять запросы т.к. он динамические. и не дай Гейтс. попадет такая обертка в цикл, начинаются "вопли" какой тормозной этот ваш ADO и т.д.. другие проблемы. а их могло бы и не быть пиши ты правильно, пусть на 1 строчку в некоторых местах и больше. экономишь строчки, теряешь производительность.
> в будущем весьма вероятно расширение функциональности. до стандартной, уже имеющейся у ADO компонент функциональности тебе ее и за год не довести... просто выработаешь у себя перманентную привычку "ездить на велосипеде собственного изготовления с треугольными колесам"
p.s. это конечно домыслы, сугубое имхо так сказать, может ты и пишешь правильно там где надо, а это используешь только подходящих под него местах. но... много раз уже видел подобное, и всегда стиль "растягивается" на все, т.е. "если увидел чайку, то и море рядом...".
-
> и закрываешь себе возможность нормальной работы с параметрами. > .. либо начинаешь городить еще и их передачу в такую функцию, > путаешься естественно, + заставляешь сервер постоянно перекомпилять > запросы т.к. он динамические. и не дай Гейтс. попадет такая > обертка в цикл, начинаются "вопли" какой тормозной этот > ваш ADO и т.д.. другие проблемы. > а их могло бы и не быть пиши ты правильно, пусть на 1 строчку > в некоторых местах и больше. > экономишь строчки, теряешь производительность.
Погоди, я не понял. Ты имеешь ввиду, что лучше В ЭТОЙ ФУНКЦИИ использовать внешнюю текстовую константу с запросом вместо того чтобы переопределять свойство SQL у компоненты, так? Я тебя понял так, что нужно вместо сервисной функции везде делать явный вызов метода. И именно с этим был не согласен.
> > в будущем весьма вероятно расширение функциональности. > > до стандартной, уже имеющейся у ADO компонент функциональности > тебе ее и за год не довести...
А это видимо ты не понял :) Я не собираюсь изобретать велосипед и переписывать компонент. Я просто забиваю на будущее возможность добавить какие-либо действия перед/после выполнения запроса. Если это не сделать, потом надо будет найти в коде все места, где выполнялся запрос, а так достаточно внести изменения в сервисную функцию.
-
> Погоди, я не понял. Ты имеешь ввиду, что лучше В ЭТОЙ ФУНКЦИИ использовать внешнюю текстовую константу с запросом вместо того чтобы переопределять > свойство SQL у компоненты, так? Я тебя понял так, что нужно вместо сервисной функции везде делать явный вызов метода. И именно с этим был не согласен.
вот изза этой фигни > ' + IntToStr(aNum) + ' запрос становиться динамическим и перекомпиляется сервером каждый раз перед выполнением, правильно статически прописать запрос, а меняемую часть сделать параметром. причем твоя функция прямо таки навязывает стиль с изменением запроса, вместо параметров (передается строка запроса). не показан способ формирования первого запроса > procedure DoDBUpdate(aNum: integer; aSQL: string); но могу "забиться" на то что там тот же стиль, с переменными сделанными частью запроса... вот это вот я и называю идиотским подходом. неважно с чем ты там несогласен.
> Я не собираюсь изобретать велосипед и переписывать компонент. поздравляю, хоть и не хотел, но начал.
> а так достаточно внести изменения в сервисную функцию. вот вот. привычка к своему велосипеду уже сказывается. вместо того чтобы изыскать методы при нормальной работе.
-
> > вот изза этой фигни > > ' + IntToStr(aNum) + ' > запрос становиться динамическим и перекомпиляется сервером > каждый раз перед выполнением, > правильно статически прописать запрос, а меняемую часть > сделать параметром. причем твоя функция прямо таки навязывает > стиль с изменением запроса, вместо параметров (передается > строка запроса). > не показан способ формирования первого запроса > > procedure DoDBUpdate(aNum: integer; aSQL: string); > но могу "забиться" на то что там тот же стиль, с переменными > сделанными частью запроса... > вот это вот я и называю идиотским подходом. неважно с чем > ты там несогласен.
Ага, дошло. Спасибо, буду думать.
> > > Я не собираюсь изобретать велосипед и переписывать компонент. > > поздравляю, хоть и не хотел, но начал.
И в чем это выражается?
> > а так достаточно внести изменения в сервисную функцию. > > вот вот. привычка к своему велосипеду уже сказывается. вместо > того чтобы изыскать методы при нормальной работе.
Что есть "методы при нормальной работе"? Писать одинаковый код в сотне мест, а затем для внесения изменений перелопачивать весь проект? Чувствую, все-таки я чего-то не понял :)
-
> Писать одинаковый код в сотне мест, а затем для внесения > изменений перелопачивать весь проект? Чувствую, все-таки > я чего-то не понял :)
Если выносишь какой то код в процедуру/метод, то надо вынести его так, чтобы было правильно. А правильно - работать с параметрами, а не генерить на кажный чих новый запрос.
|