Я поддерживаю приложение, которое работает как служба в серверной среде. Он многопоточный, где каждый поток работает в соответствии с очередью задач. Эта очередь задач представляет собой просто список строк с «типами заданий» в качестве их значений. Таким образом, хотя может выполняться несколько потоков, каждый поток будет отдельным заданием, и каждый поток внутренне выполняет только одну задачу за раз. TADODataSet
. Иногда, не всегда и без видимого шаблона, Data.Win.ADODB
выдает EArgumentOutOfRangeException
, минуя мою собственную попытку поймать любые исключения. Это исключение вешает весь поток и предотвращает его выполнение в будущем до тех пор, пока я полностью не перезапущу службу. время и изо всех сил пытались найти ответы. У меня вопрос: почему это происходит и как это остановить, поймать или исправить?
Вот фрагмент моего некорректного кода. Это метод, из которого исходит трассировка стека. Он вызывается из другого метода в том же модуле, где я открываю другой набор данных l oop через его записи, и для каждой записи вызываю эту функцию, чтобы получить некоторую информацию на основе переданного значения.
function TFQFoo.DoSomething(IncNo : Int64): string;
var
ItemList : string;
MySQL: string;
ComponentString: string;
begin
result:='';
if IncNo<=0 then
Exit;
ItemList := '';
MyQuery.Close;
MySQL := 'select ID from tbl ' +
' where val = ' + IntToStr(IncNo) +
' order by col1 DESC, col2, col3';
try
try
MyQuery.CommandText := (MySQL);
MyQuery.Open;
while not (MyQuery.EOF) do
begin
if (ItemList <> '') then
ItemList := ItemList + ',';
ItemList := ItemList +
MyQuery.FieldbyName('ID').asstring;
MyQuery.Next;
end;
except
// exception handling code omitted for brevity -- none of it
// is ever reached, anyway (see below)
end;
finally
MyQuery.Close;
end;
Result := ItemList;
end;
Стек вызовов из исключения указывает, что это происходит в Open
. Нет блока try..catch
, который захватит исключение и зарегистрирует его для меня - я должен использовать EurekaLog, чтобы увидеть какие-либо подробности. Методы трассировки стека (слишком большие, чтобы публиковать здесь) выглядят так:
- TFQFoo.DoSomething
- TDataSet.Open
- ... внутренние вещи
- TADOConnection.ExecuteComplete
- CheckForAsyncExecute
- ...
- TCustomConnection.GetDataSet
- TListHelper.GetItemRange
Thinking мой компонент TADODataSet каким-то образом повредился / его свойства изменились во время выполнения, я добавил некоторые записи для сбора этих данных для меня, чтобы я мог видеть, не происходит ли там что-то странное. Я ничего не видел, но вот это на случай, если это уместно.
object MyQuery: TADODataSet
AutoCalcFields = False
CacheSize = 15
Connection = FGlobals.RIMSDB
CursorType = ctStatic
LockType = ltReadOnly
CommandText =
'select ID from tbl where val = 202005070074 order by col1 ' +
'DESC, col2, col3'
ParamCheck = False
Parameters = <>
Left = 32
Top = 216
end
Для любопытных, это метод, который фактически генерирует исключение из Data.Win.ADODB
. Обратите внимание на except, которое, я думаю, перескакивает через мой собственный блок try..catch и отправляет исключение прямо в EurekaLog.
procedure CheckForAsyncExecute;
var
I: Integer;
begin
try
if not Assigned(pError) and Assigned(pRecordset) and
((pRecordset.State and adStateOpen) <> 0) then
for I := 0 to DataSetCount - 1 do
if (DataSets[I].Recordset = pRecordset) and (eoAsyncExecute in DataSets[I].ExecuteOptions) then
begin
DataSets[I].OpenCursorComplete;
Break;
end;
except
ApplicationHandleException(Self);
end;
end;
То, что я пробовал:
- Многие, многие итераций настройки свойств компонента в самом ADODataSet
- Использование CommandText и параметров изнутри конструктора и назначение параметра перед выполнением во время выполнения
- Добавление / удаление подсказки (NOLOCK) для сам запрос
- Передал проблему старшим членам моей команды для ввода
- Погуглил (часами)
- Чтение Delphi и документации ADO (для этого не очень полезно )
- Попытка воспроизведения - мне никогда не удавалось добиться этого ни на одной тестовой системе, которую я использую. Это заставляет меня думать, что это может быть связано с окружающей средой, но я совершенно не понимаю как
Мой вопрос, переформулированный:
Как мне остановить это от происходящего? Что я делаю не так? Я не хочу просто ловить EArgumentOutOfRangeException
; Я хочу узнать, почему это происходит в первую очередь, и предотвратить это в будущем.
Я знаю, что иногда выполнение запроса не возвращает результатов, но типичное сообщение CommandText does not return a result set
никогда не отображается и возникла из-за того, что код нижнего уровня обходит мой собственный оператор catch. Помимо этого, я не знаю, что еще искать.
До сих пор я обнаружил только одно повторение чего-то похожего, но это относится только к тому исключению, которое не было обнаружено: http://www.delphigroups.info/2/d9/410191.html