Forum Delphi.cz

Databáze => Firebird a Interbase => Téma založeno: jd 23-10-2018, 11:10:58

Název: Společná FDTransaction pro více FDConnection
Přispěvatel: jd 23-10-2018, 11:10:58
Je možné sdílet FDTransaction pro více FDConnection?.
V FDConnection.Transaction a FDQuery.Transaction nastavím společnou FDTransaction.
První FDQuery.ExecSQL končí chybou [FireDac][Phys][FB]-343 Cannot set default transaction.
Pro více IBDatabase takovéto sdílení IBTransaction jde použít.
Děkuji
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: Stanislav Hruška 23-10-2018, 11:28:18
Áno, bez problémov. Chyba bude niekde inde.
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: jd 23-10-2018, 14:42:10
Kde tedy bude chyba. Vytvoril jsem dva priklady. Button1Click je pro nesdilene FDTransaction. To projde. Button2Click je se sdilenou FDTransaction a tam to nad FDQuery1.ExecSQL skonci chybou [FireDac][Phys][FB]-343 Cannot set default transaction. Predem dekuji na nalezeni chyby. Zkouseno v Delphi 10.1

Kód: Delphi [Vybrat]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   FDConnection1, FDConnection2: TFDConnection; FDTransaction1, FDTransaction2: TFDTransaction; FDQuery1, FDQuery2: TFDQuery;
  4. begin try
  5.   FDConnection1 := nil; FDConnection2 := nil; FDTransaction1 := nil; FDTransaction2 := nil; FDQuery1 := nil; FDQuery2 := nil;
  6.   //
  7.   FDConnection1 := TFDConnection.Create(Self);
  8.   FDConnection1.Params.Add('Database=d:\Data5\HBACKUP\TEST\HM.kfb');
  9.   FDConnection1.Params.Add('User_Name=sysdba');
  10.   FDConnection1.Params.Add('Password=masterkey');
  11.   FDConnection1.Params.Add('DriverID=FB');
  12.   FDConnection1.LoginPrompt := FALSE;
  13.   FDTransaction1 := TFDTransaction.Create(Self);
  14.   FDTransaction1.Options.AutoCommit := FALSE;
  15.   FDTransaction1.Options.DisconnectAction := xdRollback;
  16.   FDConnection1.Transaction := FDTransaction1;
  17.   FDConnection1.Connected := TRUE;
  18.   //
  19.   FDConnection2 := TFDConnection.Create(Self);
  20.   FDConnection2.Params.Add('Database=d:\Data5\HBACKUP\TEST\HM2.kfb');
  21.   FDConnection2.Params.Add('User_Name=sysdba');
  22.   FDConnection2.Params.Add('Password=masterkey');
  23.   FDConnection2.Params.Add('DriverID=FB');
  24.   FDConnection2.LoginPrompt := FALSE;
  25.   FDTransaction2 := TFDTransaction.Create(Self);
  26.   FDTransaction2.Options.AutoCommit := FALSE;
  27.   FDTransaction2.Options.DisconnectAction := xdRollback;
  28.   FDConnection2.Transaction := FDTransaction2;
  29.   FDConnection2.Connected := TRUE;
  30.   //
  31.   FDTransaction1.StartTransaction;
  32.   FDQuery1 := TFDQuery.Create(Self);
  33.   FDQuery1.Connection := FDConnection1;
  34.   FDQuery1.Transaction := FDTransaction1;
  35.   FDQuery1.SQL.Text := 'insert into k$attachment (id) values(500)';
  36.   FDQuery1.ExecSQL;
  37.   FDTransaction2.StartTransaction;
  38.   FDQuery2 := TFDQuery.Create(Self);
  39.   FDQuery2.Connection := FDConnection2;
  40.   FDQuery2.Transaction := FDTransaction2;
  41.   FDQuery2.SQL.Text := 'insert into k$attachment (id) values(501)';
  42.   FDQuery2.ExecSQL;
  43.   //
  44.   FDTransaction1.Rollback;
  45.   FDTransaction2.Rollback;
  46.   ShowMessage('Ok');
  47. finally
  48.   FDConnection1.Free; FDConnection2.Free; FDTransaction1.Free; FDTransaction2.Free; FDQuery1.Free; FDQuery2.Free;
  49. end; end;
  50.  
  51. procedure TForm1.Button2Click(Sender: TObject);
  52. var
  53.   FDConnection1, FDConnection2: TFDConnection; FDTransaction: TFDTransaction; FDQuery1, FDQuery2: TFDQuery;
  54. begin try
  55.   FDConnection1 := nil; FDConnection2 := nil; FDTransaction := nil; FDQuery1 := nil; FDQuery2 := nil;
  56.   //
  57.   FDTransaction := TFDTransaction.Create(Self);
  58.   FDTransaction.Options.AutoCommit := FALSE;
  59.   FDTransaction.Options.DisconnectAction := xdRollback;
  60.   //
  61.   FDConnection1 := TFDConnection.Create(Self);
  62.   FDConnection1.Params.Clear;
  63.   FDConnection1.Params.Add('Database=d:\Data5\HBACKUP\TEST\HM.kfb');
  64.   FDConnection1.Params.Add('User_Name=sysdba');
  65.   FDConnection1.Params.Add('Password=masterkey');
  66.   FDConnection1.Params.Add('DriverID=FB');
  67.   FDConnection1.LoginPrompt := FALSE;
  68.   FDConnection1.Transaction := FDTransaction;
  69.   FDConnection1.Connected := TRUE;
  70.   //
  71.   FDConnection2 := TFDConnection.Create(Self);
  72.   FDConnection2.Params.Clear;
  73.   FDConnection2.Params.Add('Database=d:\Data5\HBACKUP\TEST\HM2.kfb');
  74.   FDConnection2.Params.Add('User_Name=sysdba');
  75.   FDConnection2.Params.Add('Password=masterkey');
  76.   FDConnection2.Params.Add('DriverID=FB');
  77.   FDConnection2.LoginPrompt := FALSE;
  78.   FDConnection2.Transaction := FDTransaction;
  79.   FDConnection2.Connected := TRUE;
  80.   //
  81.   FDTransaction.StartTransaction;
  82.   FDQuery1 := TFDQuery.Create(Self);
  83.   FDQuery1.Connection := FDConnection1;
  84.   FDQuery1.Transaction := FDTransaction;
  85.   FDQuery1.SQL.Text := 'insert into k$attachment (id) values(600)';
  86.   FDQuery1.ExecSQL;
  87.   FDQuery2 := TFDQuery.Create(Self);
  88.   FDQuery2.Connection := FDConnection2;
  89.   FDQuery2.Transaction := FDTransaction;
  90.   FDQuery2.SQL.Text := 'insert into k$attachment (id) values(601)';
  91.   FDQuery2.ExecSQL;
  92.   //
  93.   FDTransaction.Rollback;
  94.   ShowMessage('Ok');
  95. finally
  96.   FDConnection1.Free; FDConnection2.Free; FDTransaction.Free; FDQuery1.Free; FDQuery2.Free;
  97. end; end;
  98.  
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: Stanislav Hruška 23-10-2018, 15:01:31
Problém je v tom, že pristupuješ k dvom rôznym DB. A to v jednej transakcii nie je možné.
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: jd 23-10-2018, 15:57:31
V IBX (IBDatabase/IBTransaction) to mozne je.
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: KarelHorky 23-10-2018, 16:31:41
Pokud nejde ve FireDac řídit dvě databáze společnou transakcí, není to pro mně dobrá zpráva. Ve starším projektu v Delphi 7 jsem měl v komponentách IBExpres dvě databáze řízené společnou transakcí. Plánuju to časem všechno převést do nových Delphi a na FireDac. Tady pak bude nutné ponechat IBX.  :(
K.
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: Delfin 23-10-2018, 17:12:29
Pokud nejde ve FireDac řídit dvě databáze společnou transakcí, není to pro mně dobrá zpráva. Ve starším projektu v Delphi 7 jsem měl v komponentách IBExpres dvě databáze řízené společnou transakcí. Plánuju to časem všechno převést do nových Delphi a na FireDac. Tady pak bude nutné ponechat IBX.  :(
K.

A RDBMS podporuji transakce mezi connection sessions?
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: paja666 23-10-2018, 19:28:12
Citace
A RDBMS podporuji transakce mezi connection sessions?

Ano, podporuje. https://www.firebirdsql.org/pdfmanual/html/ufb-cs-multidb.html (https://www.firebirdsql.org/pdfmanual/html/ufb-cs-multidb.html)
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: Delfin 23-10-2018, 23:58:04
Citace
A RDBMS podporuji transakce mezi connection sessions?

Ano, podporuje. https://www.firebirdsql.org/pdfmanual/html/ufb-cs-multidb.html (https://www.firebirdsql.org/pdfmanual/html/ufb-cs-multidb.html)

V tom pripade to nebude neproveditelne. Jen tedy vlastnim resenim volajicim Firebird klient API. Mrknu na to az nainstaluju Delphi...
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: Delfin 24-10-2018, 14:29:35
Teoreticky by to mohlo byt mozne na fyzicke urovni (TIBTransaction totiz obsahuje kolekci databazi a pro start transakce pouziva funkci isc_start_multiple). Jen je treba rucne nastavit parametry transakce tak jak se deje uvnitr metody TFDPhysIBTransactionBase.InternalChanged. Napr. (netestovano!):

Kód: Delphi [Vybrat]
  1. uses
  2.   FireDAC.Phys.IBWrapper;
  3.  
  4. var
  5.   DatabaseOne: TIBDatabase;
  6.   DatabaseTwo: TIBDatabase;
  7.   Transaction: TIBTransaction;
  8. begin
  9.   DatabaseOne := TObject(FDConnection1.CliObj) as TIBDatabase;
  10.   DatabaseTwo := TObject(FDConnection2.CliObj) as TIBDatabase;
  11.  
  12.   Transaction := TIBTransaction.Create(DatabaseOne.Env, nil);
  13.   try
  14.     Transaction.Params.Add('write'); // nastaveni parametru transakce, viz. TFDPhysIBTransactionBase.InternalChanged
  15.  
  16.     Transaction.AddDatabase(DatabaseOne); // pridani databaze 1
  17.     Transaction.AddDatabase(DatabaseTwo); // pridani databaze 2 (lze pridat az 16)
  18.  
  19.     Transaction.StartTransaction;
  20.     try
  21.       ...
  22.       Transaction.Commit;
  23.     except
  24.       Transaction.Rollback;
  25.       raise;
  26.     end;
  27.   finally
  28.     Transaction.Free;
  29.   end;
  30. end;

Vzhledem k moznosti paralelniho startu nekolika transakci by nemelo dochazet k problemum v pripade kdy pouzite connection objekty (v ukazce FDConnection1 a FDConnection2) budou mit zrovna nastartovane vlastni transakce.

Samozrejme se takova vec da zabalit do uhledne komponenty...
Název: Re:Společná FDTransaction pro více FDConnection
Přispěvatel: Delfin 27-10-2018, 17:49:28
Kdyz nad tim ted zpetne uvazuju, asi to nebude zcela bez problemu. Objekty jenz spousti SQL prikazy totiz budou stale pozadovat od propojeneho connection objektu implicitni rizeni transakci (cemuz je treba v pripade vlastniho rizeni zamezit). Mam vsak pocit ze bylo mozne nejakym parametrem rucni rizeni nastavit. Jeste se k tomu vratim...