在执行包含多个INSERT、UPDATE、…的SQL脚本时,我在Delphi/ADO错误处理方面遇到了困难,。。。陈述只有当脚本的第一条SQL语句失败时,我才会在Delphi中得到一个异常。如果第一条语句通过,无论脚本中发生什么,Delphi中都不会出现异常。
这是我使用的Delphi代码:
var
DataSet: TADOQuery;
begin
...
try
DataSet.Close;
DataSet.ParamCheck := true;
DataSet.SQL.LoadFromFile(FileName);
DataSet.Prepared := true;
try
DataSet.ExecSQL;
finally
DataSet.Close;
end;
except
on E: Exception do
Logging.AddText(E.ClassName + ' error raised when executing ' + FileName + '. Message: ' + E.Message);
end;
...
end;
为了测试,我使用了这个简单的脚本:
INSERT INTO TESTTABLE
VALUES ('John', 24);
INSERT INTO TESTTABLE
VALUES ('Ed', '32');
其中TESTTABLE只是一个简单的表,包含两列:Name NVARCHAR(50)和Age INT。
例如,当您在第一个INSERT语句中将24替换为"twentyfour"并使用Delphi代码运行脚本时,Delphi/ADO将引发异常。但是,例如,当您在第二个INSERT语句中将32替换为"thirty2"时,也不会出现异常。
我试图通过将脚本放入存储过程"dbo.ErrorHandling"并发送来解决这个问题
EXEC dbo.ErrorHandling
到ADO,但它没有帮助。
CREATE PROCEDURE dbo.ErrorHandling
AS
BEGIN
INSERT INTO TESTTABLE
VALUES ('John', 24);
INSERT INTO TESTTABLE
VALUES ('Ed', '32');
END
我可以通过在脚本中使用TRY和CATCH来解决这个问题,并让它将错误记录到LOGGING表中。Delphi可以在每次执行脚本后检查此表中的新错误。
然而,是否有可能在Delphi中捕获所有SQL server错误,或者我是否必须执行INSERTS、UPDATES,。。。一个接一个?
我使用DelphiXE6和SQLServer2008R2
我不想看AdoConnection的错误集合。TAdoConnection.Errors
我从未找到任何方法可以同时可靠地处理多个查询并明智地检测问题。我认为正确的解决方案是一次执行一个语句。
这是我的一个程序中的代码,正是J__在评论中描述的。它处理SQL Server风格的脚本,每个语句后面都有一个GO。您可以将"GO"检测器替换为语句结束的其他指示。它将整个事务作为一个要么全有要么全无的事务进行批处理。最后一个有一些代码可以将最后一个查询保存到屏幕上的备忘录中,这样您就可以看到在出现异常时失败了什么。
procedure TDupFrame.LoadButtonClick(Sender: TObject);
var
Query: TADOQuery;
Reader: TStreamReader;
Line: string;
begin
Query := TADOQuery.Create(nil);
try
Query.Connection := ConfModule.ADOConnection;
Query.Connection.BeginTrans;
if ScriptOpenDialog.Execute(Self.Handle) then
begin
Reader := TStreamReader.Create(ScriptOpenDialog.FileName);
try
Query.SQL.BeginUpdate;
while not Reader.EndOfStream do
begin
Line := Reader.ReadLine;
if not SameText(Line, 'GO') then
begin
Query.SQL.Add(Line);
end
else
begin
Query.SQL.EndUpdate;
Query.ExecSQL;
Query.SQL.Clear;
Query.SQL.BeginUpdate;
end;
end;
Query.SQL.EndUpdate;
if Query.SQL.Count > 0 then Query.ExecSQL;
finally
Reader.Free;
end;
Query.Connection.CommitTrans;
end;
finally
SQLMemo.Lines.Assign(Query.SQL);
// rollback if we have missed the commit (ie an exception occurred)
if Query.Connection.InTransaction then
Query.Connection.RollbackTrans;
Query.Free;
end;
end;
您需要使用ExecuteNoRecords选项配置TADOQuery或TADOCommand:
Query := TADOQuery.Create(nil);
Query.ExecuteOptions := [eoExecuteNoRecords];
在.NET中也是如此。如果对SqlCommand使用ExecuteReader()或ExecuteScalar(),则无论后续有多少语句失败,如果单个命令中的第一个语句成功,都不会引发异常。
然而,如果您调用ExecuteNonQuery(),那么在任何情况下都会抛出一个适当的异常。