Ir al contenido



Foto

TFDConnection.StartTransaction vs TFDTransaction. StartTransaction

FireDAC

  • Por favor identifícate para responder
34 respuestas en este tema

#1 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 19 noviembre 2016 - 01:00

¿Cual es la diferencia en activar y cerrar una transacción entre los componentes TFDConnection y TFDTransaction?, ¿Cual me recomiendan o qué momento debo utilizar cada uno?, ocurre que en mi aplicación siempre he usado el TFDTransaction sin problemas, hasta que ocurrió una situación y es cuando se hace uso del ApplyUpdates de un TClientDataset, al usar TFDTransaction.StartTransaction el ClientDataset nunca asume que la misma está activa (El típico error Transaction must be active), sin embargo, al usar StartTransaction directamente al TFDConnection todo fluye con normalidad sin problema alguno.

 

Saludos.


  • 0

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 830 mensajes
  • LocationArgentina

Escrito 19 noviembre 2016 - 03:03

Yo siempre he manejado transacciones usando los metodos de la clase TConnection. Ya sea para ADO, FireDAC o cualquier biblioteca


  • 1

#3 santiago14

santiago14

    Advanced Member

  • Miembros
  • PipPipPip
  • 322 mensajes
  • LocationCerrillos - Salta - Argentina

Escrito 20 noviembre 2016 - 05:39

Mmmmm. Lo natural sería que las transacciones sean manejadas por el componente "Transacción"
Es raro el error...


Enviado desde mi iPhone utilizando Tapatalk
  • 1

#4 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 830 mensajes
  • LocationArgentina

Escrito 20 noviembre 2016 - 11:58

La documentacion explica, de una manera bastante chapucera, que TFDTransaction esta mas orientado para desarrollos con Interbase o Firebird, esto es porque estos DBMS soportan multiples transacciones. El componente permite conectar un determinado query o command con una transaccion particular


  • 0

#5 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 20 noviembre 2016 - 12:14

Note: The use of the TFDTransaction component is optional in FireDAC

 

 

¿Y por qué FireDAC me obliga a usarla?, si es opcional no debería forzarnos a utilizarlo, ¿no?.


  • 0

#6 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 830 mensajes
  • LocationArgentina

Escrito 20 noviembre 2016 - 12:29

Y en que momento te obliga a usarla? Yo jamas use un componente para transaccion porque no tuve la necesidad. Simplemente manejo todo con el componente Connection


  • 0

#7 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 20 noviembre 2016 - 12:40

Me refiero a que hay que colocar un componente TFDTransaction, ya que cuando intentas conectarte al TFDConnection te pide que lo vincules con un TFDTransaction.


  • 0

#8 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 830 mensajes
  • LocationArgentina

Escrito 20 noviembre 2016 - 01:13

No es necesario, como decia, nunca he usado el componente, ni en tiempo de diseño, ni creandolo en tiempo de ejecucion


  • 0

#9 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 25 mayo 2017 - 01:41

Retomo el tema con algo que tiene relación, leí en el doc de embarcadero, que hay que utilizar un TFDTransaction particular para cada operación, aquí estoy un poco confundido, porque estoy teniendo algunos problemas que creo que está relacionado con ellos, me explico, tengo esto (ejemplo):


delphi
  1. Datos.dbDatos.StartTransaction; //Esto es un TFDConnection y tiene un TFDTransaction vinculado
  2. if ID > 0 then begin
  3. GeneraOrden(ID); //No esta ligado a una transaccion,
  4. GuardaDetalles(ID); //No esta ligado a una transaccion,
  5. ActualizaStock(ID); //No esta ligado a una transaccion,
  6. ...
  7. end;
  8. Datos.dbDatos.Commit;

Mi pregunta es según la doc se le debe asignar un TFDTransaction a cada procedimiento ó función?, o sea,


delphi
  1. Datos.dbDatos.StartTransaction; //Esto es un TFDConnection y tiene un TFDTransaction vinculado
  2. if ID > 0 then begin
  3. GeneraOrden(ID); //Un TFDTransaction (trGeneracion), AutoCommit?
  4. GuardaDetalles(ID); //Un TFDTransaction (trDetalles), AutoCommit?
  5. ActualizaStock(ID); //Un TFDTransaction (trActualiza), AutoCommit?
  6. ...
  7. end;
  8. Datos.dbDatos.Commit;

¿Cómo lo hacen ustedes?


  • 0

#10 santiago14

santiago14

    Advanced Member

  • Miembros
  • PipPipPip
  • 322 mensajes
  • LocationCerrillos - Salta - Argentina

Escrito 25 mayo 2017 - 02:04

Retomo el tema con algo que tiene relación, leí en el doc de embarcadero, que hay que utilizar un TFDTransaction particular para cada operación, aquí estoy un poco confundido, porque estoy teniendo algunos problemas que creo que está relacionado con ellos, me explico, tengo esto (ejemplo):


delphi
  1. Datos.dbDatos.StartTransaction; //Esto es un TFDConnection y tiene un TFDTransaction vinculado
  2. if ID > 0 then begin
  3. GeneraOrden(ID); //No esta ligado a una transaccion,
  4. GuardaDetalles(ID); //No esta ligado a una transaccion,
  5. ActualizaStock(ID); //No esta ligado a una transaccion,
  6. ...
  7. end;
  8. Datos.dbDatos.Commit;

Mi pregunta es según la doc se le debe asignar un TFDTransaction a cada procedimiento ó función?, o sea,


delphi
  1. Datos.dbDatos.StartTransaction; //Esto es un TFDConnection y tiene un TFDTransaction vinculado
  2. if ID > 0 then begin
  3. GeneraOrden(ID); //Un TFDTransaction (trGeneracion), AutoCommit?
  4. GuardaDetalles(ID); //Un TFDTransaction (trDetalles), AutoCommit?
  5. ActualizaStock(ID); //Un TFDTransaction (trActualiza), AutoCommit?
  6. ...
  7. end;
  8. Datos.dbDatos.Commit;

¿Cómo lo hacen ustedes?

 

Cómo lo uso yo...

Tengo un componente: TFDConnection --> se conecta a la BBDD

Tengo un componente: TFDTransaction --> asociado a TFDConnection

Ahora bien, tengo varios componente TFDQuery --> asociados a TFDTransaction (propiedad Transaction) y también asociados a TFDConnection (propiedad Connection)

 

Dentro de las Query's hago las SQL's que sean necesarias.

 

En el código siempre pongo:


delphi
  1. TFDTransaction.StartTransaction;
  2. //Las consultas que sean necesarias
  3.  
  4. TFDTransaction.Commit;

Espero haber sido claro.

 

Santiago


  • 0

#11 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 25 mayo 2017 - 02:14

Gracias santiago, originalmente lo tenía de esa forma, el problema que tenía era que al hacer commit a través del TFDTransaction los datos no se reflejaban sino hasta que se desconectara la BD, o sea, Cerrar el sistema, por eso lo hago con TFDConnection directamente, y segundo, al ser un sólo TFDTransaction, no sé si al usarlo en varios sitios al mismo tiempo provocaba un tranque, o que las mismas se quedaban en el limbo y la numeración de la orden no se reflejaba y más adelante es utilizado por otros movimientos, creando un caos de informaciones que se pierden en un determinado momento (Es un sistema multi-usuario en red), la verdad me tiene desconcertado el asunto.

 

Saludos.


  • 0

#12 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 830 mensajes
  • LocationArgentina

Escrito 25 mayo 2017 - 03:06

Habra que investigarlo, la documentacion no es del todo clara:

 

http://docwiki.embar...tions_(FireDAC)

 

 

Alternatively, the application can use the explicit transaction control. For this, use the TFDConnection methods StartTransaction, Commit, Rollback. An alternative to this is the use of the TFDTransaction component.

 

Note: The use of the TFDTransaction component is optional in FireDAC.

 

Ejemplo de la misma pagina en la documentacion del codigo "estandar" para manejo de transacciones:


delphi
  1. FDConnection1.StartTransaction;
  2. try
  3. FDQuery1.ExecSQL;
  4. ....
  5. FDQuery1.ExecSQL;
  6. FDConnection1.Commit;
  7. except
  8. FDConnection1.Rollback;
  9. raise;
  10. end;

Asi lo he hecho yo siempre con todas las distintas familias de componentes, jamas tuve un problema.

 

Nota sobre TFDTransaction, tambien del mismo link de arriba:

 

 

The TFDTransaction component wraps the transaction control functionality into a component. Practically, it offers the same transaction functionality as TFDConnection, but allows you to group commands and datasets by linking them to a specific transaction object. At first, this refers to the multiple active transactions support, that is the Interbase and Firebird server features.

 

Que es justamente lo que he dicho en las primeras respuestas del hilo, el TFDTransaction es para tener multiples transacciones activas al mismo tiempo y tener un par de queries/command con el TFDTransaction #1 y otro conjunto de queries y command asociados con el TFDTransaction #2, calculo que esto servira para incrementar performance cuando varios procesos se pueden ejecutar en paralelo (porque operan en distintas tablas, con distintos datos, etc)

 

http://docwiki.embar...ve_Transactions

 

 

 

Firebird and InterBase support multiple active transactions on the DBMS core level. This means that some commands may be performed in one transaction context, others in the second transaction context, and so on. To support this feature, FireDAC provides the TFDTransaction component. Its single instance allows you to handle single transactions at any given moment

 

No todas las BD soportan esto y por eso la doc. aclara que, en un principio, solo tiene sentido en Firebird e Interbase

 

---

 

Por otra parte:

 

http://docwiki.embar...tartTransaction

 

 

The StartTransaction call is the shortcut to Transaction.StartTransaction, if the Transaction property is assigned. Otherwise StartTransaction will operate on the default connection transaction.

 

En definitiva, FDConnection.StartTransaction == FDConnection.Transaction.StartTransaction. Probablemente el componente FDConnection cree la instancia del Transaction si esta es nil cuando llamamos a StartTransaction


  • 0

#13 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 25 mayo 2017 - 05:24

Gracias Agustín, por la aclaración, por ahí leí que los DataSets de FireDAC tienen dos propiedades para asignarles sus transacciones, como son TFDQuery1.Transaction y TFDQuery1.UpdateTransaction, lo estoy implementado desde hace días la forma en que presenta el ejemplo de la doc:


delphi
  1. UpdateTransaction: TFDTransaction;
  2. ReadTransaction: TFDTransaction;
  3. ...
  4. // setup transaction for updating commands: read_committed, rec_version, nowait
  5. UpdateTransaction.Connection := FDConnection1;
  6. FDConnection1.UpdateOptions.LockWait := False;
  7. UpdateTransaction.Options.ReadOnly := False;
  8. UpdateTransaction.Options.Isolation := xiReadCommitted;
  9. ...
  10. ReadTransaction.Connection := FDConnection1;
  11. ReadTransaction.Options.ReadOnly := True;
  12. ReadTransaction.Options.Isolation := xiReadCommitted;
  13. ...
  14. SelectQuery.Transaction := ReadTransaction;
  15. SelectQuery.UpdateTransaction := UpdateTransaction;

así que lo tengo así:


delphi
  1. Datos.dbDatos.StartTransaction; //Esto es un TFDConnection y tiene un TFDTransaction vinculado
  2. if ID > 0 then begin
  3. GeneraOrden(ID); //Un TFDTransaction en UpdateTransaction (trGeneracion), AutoCommit
  4. GuardaDetalles(ID); //Un TFDTransaction en UpdateTransaction (trDetalles), AutoCommit
  5. ActualizaStock(ID); //Un TFDTransaction en UpdateTransaction (trActualiza), AutoCommit
  6. ...
  7. end;
  8. Datos.dbDatos.Commit;

Hasta ahora no se me ha presentado inconvenientes, y espero que siga así, dejadme explicarle mi situación, mi sistema tiene un módulo de almacén y se realizan constante salidas de partes e insumos, hay de 3 a 4 usuarios trabajando al mismo tiempo, sucede que, hasta cierto punto el número de salida que se genera se van guardando correctamente y despúes deja de guardarse aunque aparenta que todo está correcto, se genera la orden y se imprime la salida correctamente, pero se pierde esa información y luego de un momento a otro vuelve a guardarse los datos pero ocupando la continuidad de salidas que ya se hicieron, me explico:

 

ordenes no.

100

101

102

103

104 <---hasta aqui todo bien, se guarda la info en la BD

105 <---

106      |

107      | Esos aparentan estar correctos se imprime y todo pero no se guarda en la BD

108      | Y no marcan error alguno, es como que se quedaran esperando el commit,¿ WTF?

109 <---

110 <---

111      |

112      | Esos se supone serían la continuación, pero en realidad

113      | asumen la numeración anterior y sí se graban correctamente y los anteriores se pierden ¿DOBLE WTF?

114 <---

 

Espero que la implementación anterior sea la solución, y si alguien ha experimentado algo parecido por favor haganme saberlo.

 

Saludos.


  • 0

#14 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 25 mayo 2017 - 05:27

una aclaración, en los procedimientos y funciones dentro de StartTransaction y Commit de Datos.dbDatos, no incluían su propio StartTransaction y Commit, tal vez el problema venga por esos lados, pero ya les informo en un par de días.


  • 0

#15 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 830 mensajes
  • LocationArgentina

Escrito 25 mayo 2017 - 08:39


delphi
  1. Datos.dbDatos.StartTransaction; //Esto es un TFDConnection y tiene un TFDTransaction vinculado
  2. if ID > 0 then begin
  3. GeneraOrden(ID); //Un TFDTransaction en UpdateTransaction (trGeneracion), AutoCommit
  4. GuardaDetalles(ID); //Un TFDTransaction en UpdateTransaction (trDetalles), AutoCommit
  5. ActualizaStock(ID); //Un TFDTransaction en UpdateTransaction (trActualiza), AutoCommit
  6. ...
  7. end;
  8. Datos.dbDatos.Commit;

Si la transaccion inica correctamente, y dentro de los procedimientos GeneraOrden, GuardaDetalles y ActualizaStock no hay ningun "manejo raro" de transacciones, es decir, no haces commit ni nada, no deberia dar problemas (lo que comentaste ultimo indica que no tocas la transaccion ahi dentro)
 
Si tampoco hay excepciones no se me ocurre mucho mas a simple vista
 
A lo mejor sea cuestion de jugar con las propiedades de la Transaccion o de la Conexion (que en FireDAC hay millones de propiedades..)
  • 0

#16 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 26 mayo 2017 - 07:17

Se me ocurre también que podría que estoy creando los datasets en memoria, casi todos, o sea:


delphi
  1. function GeneraOrden(const ADatos: TOrden): Integer;
  2. var Query: TFDQuery;
  3. begin
  4.  
  5. Result := 0;
  6.  
  7. Query := TFDQuery.Create(nil);
  8. try
  9. Query.Connection := Datos.dbDatos;
  10. Query.UpdateTransaction := Datos.trGeneracion; //He agregado esta linea
  11. ...
  12. ...
  13. Result := Query.Fields[0].asInteger;
  14. finally
  15. Query.free
  16. end;
  17. end;

No sé si al liberar el objeto pueda afectar las transacciones ó el guardado de los datos al hacer commit.


  • 0

#17 santiago14

santiago14

    Advanced Member

  • Miembros
  • PipPipPip
  • 322 mensajes
  • LocationCerrillos - Salta - Argentina

Escrito 26 mayo 2017 - 07:37

Gracias santiago, originalmente lo tenía de esa forma, el problema que tenía era que al hacer commit a través del TFDTransaction los datos no se reflejaban sino hasta que se desconectara la BD, o sea, Cerrar el sistema, por eso lo hago con TFDConnection directamente, y segundo, al ser un sólo TFDTransaction, no sé si al usarlo en varios sitios al mismo tiempo provocaba un tranque, o que las mismas se quedaban en el limbo y la numeración de la orden no se reflejaba y más adelante es utilizado por otros movimientos, creando un caos de informaciones que se pierden en un determinado momento (Es un sistema multi-usuario en red), la verdad me tiene desconcertado el asunto.

 

Saludos.

 

 

En este momento estoy al frente de una PC, viendo la ejecución de un software que tenemos aquí. 

Veo que hay 51 usuarios en simultáneo trabajando sin ningún problema. Si bien no es mucho, ayuda para entender eso de la simultaneidad. Aclaro que estoy usando Firebird 2.5 y FireDAC de Delphi XE5

En el caso de todos estos usuarios, cuando hacen Commit o Rollback, todos pueden ver los cambios inmediatamente después.

Transcribo un pedacito de código real de un módulo del software ese y pongo algunas aclaraciones:


delphi
  1. procedure TfrmGestionSumarios.btnBuscarClick(Sender: TObject);
  2. var
  3. fecha:TDate;
  4. estado, condicion_sumario:string;
  5. begin
  6. fecha:=dtFechaSumario.Date;
  7. with DataModule1 do
  8. begin
  9. terminarTransaccion;
  10. try
  11. transaccion.StartTransaction;
  12. estado:='';
  13. condicion_sumario:=self.condicion_sumario(rgTipoSumario.ItemIndex);
  14. consultaSumario(gCodigo_Sucursal, fecha, qSumarios, estado, condicion_sumario);
  15. limpiarGrilla(gSumarios);
  16. cargarTStringGrid(gSumarios, qSumarios);
  17. txtCantidadAvisos.Text:=IntToStr(gSumarios.RowCount - 2);
  18. transaccion.Commit;
  19. gSumarios.SetFocus;
  20. except
  21. on e:Exception do
  22. begin
  23. terminarTransaccion;
  24. mErrores(e, 'La consulta no pudo realizarse', lblTituloGestionSumario.Caption);
  25. end;
  26. end;
  27. end;
  28. end;

TerminarTransaccion:


delphi
  1. procedure terminarTransaccion; overload;
  2. begin
  3. with DataModule1 do
  4. if boletin.InTransaction then
  5. transaccion.Rollback;
  6. end;

ConsultaSumario es la Consulta SQL.

transaccion es un TFDTransaction y está asociado a un TFDConnection como puse mas arriba.

qSumarios es un TFDQuery que está enganchado al TFDTransaction.

 

Es raro eso que se veían los cambios recién después de cerrar el sistema, tal vez tenga que ver con el nivel de aislamiento. Al respecto, en la propiedad Isolation de mi TFDTransaction tengo: Isolation = xiReadCommited

 

Pongo la función mErrores, tal vez te pueda servir para decirte de mejor manera que es lo que pasa.


delphi
  1. procedure mErrores(e:FireDAC.Phys.IBWrapper.EIBNativeException; tituloErrorGeneral:string; subtitulo:string); overload;
  2. begin
  3. case e.ErrorCode of
  4. 335544352:
  5. begin
  6. Application.MessageBox(pchar('Lo siento, no tienes autorización para realizar esta acción.'
  7. + #13#10 + 'Mensaje: ' + e.message), pchar(subtitulo), MB_OK + MB_ICONERROR);
  8. end;
  9. 335544665:
  10. begin
  11. Application.MessageBox(pchar('El registro que intentas ingresar ya existe (Violación de Clave primaria)'
  12. + #13#10 + 'Mensaje: ' + e.Message), pchar(subtitulo),MB_OK + MB_ICONERROR);
  13. end;
  14. 335544472:
  15. begin
  16. Application.MessageBox('Nombre de Usuario y/o Contraseña son incorrectos',
  17. pchar(subtitulo),MB_OK + MB_ICONERROR);
  18. end;
  19. else
  20. Application.MessageBox(PWideChar(tituloErrorGeneral + #13#10 + 'Mensaje: ' + e.Message
  21. + #13#10 + 'Nro de Error: ' + intToStr(e.ErrorCode)),
  22. //+ #13#10 + 'SQL Code Error: ' + intToStr(e.sqlcode)),
  23. PWideChar(subtitulo),MB_OK + MB_ICONERROR);
  24. end; //del case
  25. end;
  26.  
  27. procedure mErrores(e:Exception;tituloErrorGeneral:string;subtitulo:string); overload;
  28. begin
  29. Application.MessageBox(PWideChar(tituloErrorGeneral + #13#10 + 'Mensaje: ' + e.Message),
  30. PWideChar(subtitulo), MB_OK + MB_ICONERROR);
  31. end;

Espero haber ayudado.


  • 2

#18 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 26 mayo 2017 - 07:49

Gracias Santiago, la verdad no sé donde está mi problema, puede ser que existe alguna intermitencia en la red ó actividades paranormales, porque en principio estaba trabajando tal como lo presentas salvo lo de terminarTransaccion, reitero gracias.


  • 0

#19 santiago14

santiago14

    Advanced Member

  • Miembros
  • PipPipPip
  • 322 mensajes
  • LocationCerrillos - Salta - Argentina

Escrito 26 mayo 2017 - 07:58

Gracias Santiago, la verdad no sé donde está mi problema, puede ser que existe alguna intermitencia en la red ó actividades paranormales, porque en principio estaba trabajando tal como lo presentas salvo lo de terminarTransaccion, reitero gracias.

 

Por nada compañero.

Un saludo.


  • 0

#20 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.948 mensajes
  • LocationMéxico

Escrito 26 mayo 2017 - 08:02

[OFF TOPIC]

 

..... ó actividades paranormales, .....

 

:D :D :D

 

Saludos


  • 0





Etiquetado también con una o más de estas palabras: FireDAC