事务中的多个参数化Delphi SQL更新

时间:2015-07-10 18:03:40

标签: sql-server delphi sqlite transactions parameterized

我正在尝试使用Delphi XE8中的参数化查询在同一循环中更新两个不同的SQL表。我还希望将整个事物包装在一个事务中,这样如果循环中的任何内容都失败,那么这两个表都不会更新。

我真的不知道我在做什么,会感激一些帮助。

下面的代码是我想要实现的简化版本,我最好的猜测是如何去做。但我根本不确定它,特别是使用连接到“SQL连接”组件的两个数据集。

SQL_transaction.TransactionID :=1;
SQL_transaction.IsolationLevel:=xilREADCOMMITTED;
SQL_connection.BeginTransaction;
Try
  { Create connections }

  SQL_dataset1              :=TSQLDataSet.Create(nil);  
  SQL_dataset1.SQLConnection:=SQL_connection;

  SQL_dataset2              :=TSQLDataSet.Create(nil);  
  SQL_dataset2.SQLConnection:=SQL_connection;

  { Create queries }

  SQL_dataset1.CommandType:=ctQuery;
  SQL_dataset1.CommandText:={ some parameterized query updating table A }

  SQL_dataset2.CommandType:=ctQuery;
  SQL_dataset2.CommandText:={ some parameterized query updating table B }

  { Populate parameters and execute }

  For I:=0 to whatever do
  begin
    SQL_dataset1.ParamByName('Table A Field 1').AsString:='Value';
    SQL_dataset1.ExecSQL; 

    SQL_dataset2.ParamByName('Table B Field 1').AsString:='Value';
    SQL_dataset2.ExecSQL; 
  end;

  SQL_connection.Commit(SQL_transaction);
except
  SQL_connection.Rollback(SQL_transaction);  
end;

我使用的是Delphi XE8,数据库可以是SQL服务器,也可以是SQLite。

2 个答案:

答案 0 :(得分:4)

您的事务处理逻辑是正确的(除了@whosrdaddy提到的丢失的异常重新提升)。有什么问题是数据集实例缺少try..finally块。除非您应停止使用TTransactinDesc已弃用的TSQLQuery记录方法(在您构建应用时始终检查编译器警告。)。您还可以切换到var I: Integer; Query1: TSQLQuery; Query2: TSQLQuery; Connection: TSQLConnection; Transaction: TDBXTransaction; begin ... Query1 := TSQLQuery.Create(nil); try Query1.SQLConnection := Connection; Query1.SQL.Text := '...'; Query2 := TSQLQuery.Create(nil); try Query2.SQLConnection := Connection; Query2.SQL.Text := '...'; Transaction := Connection.BeginTransaction; try // fill params here and execute the commands for I := 0 to 42 to begin Query1.ExecSQL; Query2.ExecSQL; end; // commit if everything went right Connection.CommitFreeAndNil(Transaction); except // rollback at failure, and re-raise the exception Connection.RollbackFreeAndNil(Transaction); raise; end; finally Query2.Free; end; finally Query1.Free; end; end; 组件。尝试这样的事情:

php artisan serve

答案 1 :(得分:-1)

我更喜欢尝试尝试除了

这里是如何让它在try finally块中运行

var
  a_Error: boolean;
begin
a_Error := True;//set in error state...
SQL_dataset1 := nil;
SQL_dataset2 := nil;
SQL_transaction.TransactionID :=1;
SQL_transaction.IsolationLevel:=xilREADCOMMITTED;
SQL_connection.BeginTransaction;

Try
  { Create connections }

  SQL_dataset1              :=TSQLDataSet.Create(nil);  
  SQL_dataset1.SQLConnection:=SQL_connection;

  SQL_dataset2              :=TSQLDataSet.Create(nil);  
  SQL_dataset2.SQLConnection:=SQL_connection;

  { Create queries }

  SQL_dataset1.CommandType:=ctQuery;
  SQL_dataset1.CommandText:={ some parameterized query updating table A }

  SQL_dataset2.CommandType:=ctQuery;
  SQL_dataset2.CommandText:={ some parameterized query updating table B }

  { Populate parameters and execute }

  For I:=0 to whatever do
  begin
    SQL_dataset1.ParamByName('Table A Field 1').AsString:='Value';
    SQL_dataset1.ExecSQL; 

    SQL_dataset2.ParamByName('Table B Field 1').AsString:='Value';
    SQL_dataset2.ExecSQL; 
  end;

  a_Error := False;//if you don't get here you had a problem
finally
  if a_Error then
    SQL_connection.Rollback(SQL_transaction)
  else
    SQL_connection.Commit(SQL_transaction);
  SQL_dataset1.Free;
  SQL_dataset2.Free;

end;    
end;

我添加了一些关于Try Finally如何使用init对象到nil

的代码
  TMyObject = class(TObject)
    Name: string;
  end;

procedure TForm11.Button1Click(Sender: TObject);
var
  a_MyObject1, a_MyObject2: TMyObject;
begin
  a_MyObject1 := nil;
  a_MyObject2 := nil;
  try
    a_MyObject1 := TMyObject.Create;
    a_MyObject1.Name := 'Object1';
    if Sender = Button1 then    
      raise exception.Create('Object 2 not created');
    ShowMessage('We will not see this');
    a_MyObject2 := TMyObject.Create;
    a_MyObject2.Name := 'Object2';
  finally
    a_MyObject2.Free;
    ShowMessage('We will see this even though we called a_MyObject2.free on a nil object');
    a_MyObject1.Free;
  end;
end;