Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Problema al grabar un Master/Detail el detalle no se graba... (https://www.clubdelphi.com/foros/showthread.php?t=65955)

Ricardojosep 24-01-2010 13:54:17

Problema al grabar un Master/Detail el detalle no se graba...
 
Hola amigos, despues de mucho tiempo de no programar nada en delphi, vulevo a uds para hacer un consulta que me tiene molesto... espero tengan respuesta a este problema!

Tengo un servidor linux, con firebird 2.1 instalado... dos usuarios con windows XP y 2000 y el sistema desarrollado en D6 con componentes zeos que se conectan al Firebird del servidor linux. Hasta ahora todo perfecto, cuando el sistema comienza a funcionar, todo fue de 10 puntos, pero despues de un tiempo, cuando ya habia casi 40000 facturas de venta cargadas, comenzaron los problemas, resulta que cuando los operadores intentan grabar una nueva factura, la misma no se graba, pero el sistema no emite ningun error, no se graba ni el Maestro ni el detalle. Se tiene que cerrar la aplicacion para que vuelva a funcionar.

El proceso de grabacion se hace mediante un starttransaction y se finaliza con un commite.

Realmente necesito ayuda, no se que puede estar pasando, muchas gracias desde ya!

Saludos!

Ricardo.

Casimiro Notevi 24-01-2010 15:54:45

Cita:

Empezado por Ricardojosep (Mensaje 351701)
Hola amigos,[..]Saludos! Ricardo.

Hola, amigo, es bien difícil ayudarte con tan pocos datos, pon por aquí algo de código para que podamos evaluar.

marcoszorrilla 24-01-2010 17:48:04

A mi la única vez que me ha pasado algo parecido, es decir que no grababa nada ni daba error fué porque a un IbDataset le puse sin darme cuenta la propiedad CacheUpdates a True.



Un Saludo.

Ricardojosep 25-01-2010 12:42:54

Aqui va el codigo
 
Hola Casimiro, Marcos, muchas gracias por su respuesta. Aqui paso a poner el codigo que hace delphi para hacer el grabado en la base, realmente todo se hace por procedimiento almacenado, asique pongo las dos cosas...

Código Delphi [-]
Base.StartTransaction;
Error := False;
Estado := True;
GrabaVenta.ParamByName('ITOTAL').AsFloat := StrToFloat(TotalPesos.Caption);

Try
  GrabaVenta.ExecProc;
Except
  Error := True;
End;

For I := 1 To DetalleVenta.RowCount - 1 Do
  Begin
    GrabaDetalleVenta.ParamByName('IFACTURA').AsInteger := GrabaVenta.ParamByName('Factura').AsInteger;
    GrabaDetalleVenta.ParamByName('IITEM').AsInteger := StrToInt(DetalleVenta.Cells[0, I]);
    GrabaDetalleVenta.ParamByName('IID').AsInteger := StrToInt(DetalleVenta.Cells[1, I]);
    GrabaDetalleVenta.ParamByName('ICANTIDAD').AsInteger := StrToInt(DetalleVenta.Cells[3, I]);
    GrabaDetalleVenta.ParamByName('IPRECIO').AsFloat := StrToFloat(DetalleVenta.Cells[4, I]);

     Try
       GrabaDetalleVenta.ExecProc;
     Except
        Error := True;
     End;
  End;

If Not Error Then
  Base.Commit;
Else
  Base.Rollback;

Ahora bien, los procedimientos almacenados que realizan la grabacion, son:

Grabar_Factura;

Código SQL [-]
=============================================================================
DECLARE VARIABLE fact BIGINT;
BEGIN
  /* Procedure body */
  SELECT gen_id(Ventas_Factura_GEN,1) FROM RDB$DATABASE INTO :fact;
  INSERT INTO ventas VALUES (:fact, 'A', '', current_date, current_time, :itotal);
  factura = :fact;
  SUSPEND;
END
=============================================================================
Parameters:
ITOTAL                            INPUT DOUBLE PRECISION
FACTURA                           OUTPUT BIGINT

y Grabar_Detalle_Factura;

Código SQL [-]
=============================================================================
BEGIN
  /* Procedure body */
  INSERT INTO detalle_venta VALUES (:iFACTURA, :iITEM, :iID, :iCANTIDAD, :iPRECI
O, :iDESCUENTO);
  SUSPEND;
END
=============================================================================
Parameters:
IFACTURA                          INPUT BIGINT
IITEM                             INPUT INTEGER
IID                               INPUT INTEGER
ICANTIDAD                         INPUT INTEGER
IPRECIO                           INPUT DOUBLE PRECISION
IDESCUENTO                        INPUT SMALLINT

Con respecto a lo que me dice Marcos la propiedad CachedUpdates del TZStoreProc esta en false...

Muchas gracias por la ayuda, hasta luego!

Saludos!!

Ricardo

Casimiro Notevi 25-01-2010 12:57:04

Cita:

Empezado por Ricardojosep (Mensaje 351701)
[..] cuando los operadores intentan grabar una nueva factura, la misma no se graba, pero el sistema no emite ningun error, no se graba ni el Maestro ni el detalle. Se tiene que cerrar la aplicacion para que vuelva a funcionar. [..]

Y cuando abres el programa, la primera vez ¿sí funciona?

Ricardojosep 25-01-2010 13:31:48

Hola Casimiro, gracias por tu rapida respuesta, Si el sistema funciona siempre... solo hay pocas veces que pasa esto...

Saludos!!!

Ricardo

Casimiro Notevi 25-01-2010 13:52:24

Veo que inicias con un 'Base.StartTransaction', ¿los componentes zeos tienen algún método para finalizar la transacción, 'Base.EndTransaction' o basta con hacer con el commit?.

Ricardojosep 25-01-2010 13:59:48

Hola Casimiro, nuevamente muchas gracias!!

Pues me has hecho dudar, y me he fijado si existe algun EndTransaction o algo parecido, pero no... solo eso...

Tambien estuve viendo el TransactionIsolationLevel y esta en TiReadCommitted

Pues realmente ya no se si ese valor esta bien o no...

En fin, muchas gracias!!

Saludos!

Ricardo

guillotmarc 25-01-2010 13:59:56

Hola.

Con tu código los errores quedan ocultos, ya que no salta ningún mensaje al usuario, simplemente haces un Rollback y por tanto no se graban los datos (que es el problema que comentas, no se graban datos sin ninguna razón aparente).

Deberías hacer que cuando haya errores se muestren o al menos se informe al usuario de que sus datos no serán guardados.

Código:

exception
  Error := True;
  on E: Exception do ShowMesasage('Error: ' + E.Message);
end;

Por cierto, ¿ tienes triggers en esas tablas ?, los triggers pueden ser el motivo de que a veces no se inserten algunos registros. Si el trigger falla entonces no se graban los datos.

Saludos.

Ricardojosep 25-01-2010 14:05:44

Hola guillotemarc, pues los errores se muestran, me olvide de poner eso el mensaje anterior... el error que se ve pasa como parametro y se muestra el error en otro procedimiento de delphi, y los operadores me dicen que el mensaje no aparece... El mensaje es del tipo ShowMessage('ERROR...') asique ellos tienen que hacer un click para cerrar el cuadro de dialogo para continuar..

Muchas gracias!!

Saludos!!

Ricardo

Ricardojosep 25-01-2010 14:07:34

Hola nuevamente guillotemarc, me olvide de decirte que si tengo triggers en las tablas, graban los logs... pues como deberia hacer los logs si no los hago con los triggers, el sistema se pondria mas lento, o no?

Muchas gracias!!

Saludos!!!

guillotmarc 25-01-2010 14:08:27

Cita:

Empezado por Ricardojosep (Mensaje 351759)
Pues me has hecho dudar, y me he fijado si existe algun EndTransaction o algo parecido, pero no... solo eso...

Tambien estuve viendo el TransactionIsolationLevel y esta en TiReadCommitted

No conozco las Zeos pero al hacer un Commit ya basta para asegurar que los datos sean guardados, no se necesita ninguna finalización posterior de la transacción (esta solo sería para liberar el componente de memoria, no para confirmar la transacción).

Respecto al nivel de aislamiento, el Read Commited es muy estándar y perfectamente válido para este caso. Aunque el nivel por defecto en Firebird es SnapShot (que muchos componentes no lo reconocen porqué es propio de Firebird) el problema no debería estar ahí.

guillotmarc 25-01-2010 14:12:20

Cita:

Empezado por Ricardojosep (Mensaje 351763)
Hola guillotemarc, pues los errores se muestran, me olvide de poner eso el mensaje anterior... el error que se ve pasa como parametro y se muestra el error en otro procedimiento de delphi, y los operadores me dicen que el mensaje no aparece... El mensaje es del tipo ShowMessage('ERROR...') asique ellos tienen que hacer un click para cerrar el cuadro de dialogo para continuar..

Entonces tu código no es ese, sino que es más complejo. Ya que con ese código Delphi que nos has enseñado el programa se come los errores y ocurre lo que dices: no se muestra ningún mensaje ni se guardan los datos.

Será mejor que compruebes que realmente los errores se muestran (provoca uno adrede, por ejemplo con un error en el SQL de la consulta para guardar).

Saludos.

guillotmarc 25-01-2010 14:15:25

Cita:

Empezado por Ricardojosep (Mensaje 351764)
Hola nuevamente guillotemarc, me olvide de decirte que si tengo triggers en las tablas, graban los logs... pues como deberia hacer los logs si no los hago con los triggers, el sistema se pondria mas lento, o no?

Hola, yo también hago los Logs con triggers.

No hay ningún problema en ello, pero como cualquier otra cosa pueden fallar. En principio el error ya te indicaría el trigger que falla y la razón, a mi me parece que tu problema es que tu código está ocultando los errores (ya sea en la base de datos o en tu programa).

Saludos.

Ricardojosep 26-01-2010 12:13:36

Gracias guillotemarc, ahora voy a poner los errores en pantalla para ver que puede estar pasando, cualquier cosa vuelvo con el hilo.

Muchas gracias a todos!!

Saludos!!

Ricardojosep 27-01-2010 23:34:21

Hola de nuevo, sigo con el problema, pero ahora hice lo que me dijo guillotemarc y grabe los errores en un archivo de texto... el primer error que me aparece es: -901 Lock conflict on no wait transaction. Este error se produce en un Procedimiento Almacenado, que es el que se encarga de actualizar el stock. El problema esta que cuando los operadores cargan una compra, para incrementar el stock y después de un corto tiempo, mas o menos 30 segundo, se hace una venta y produce este error. Mi gran pregunta es: ¿Porque se produce un bloqueo si la primera transacción (compra) finaliza primero, y después se inicia la otra...?

En fin, de todas maneras, muchas gracias por la ayuda que me dieron!!

Saludos!!!

Ricardo

Casimiro Notevi 27-01-2010 23:47:34

Habría que ver ese código, cuando haces commit y eso... pero en principio puedes cambiar las transacciones a "no wait".

Yo siempre lo pongo así:

Código:

write
nowait
rec_version
read_committed


Ricardojosep 27-01-2010 23:55:19

Hola Casimiro, voy a probar de cambiar la transacción a no wait, pero a mi me resulta muy extraño... porque se supone que la transacción finaliza y despues de un tiempo comienza la otra... y lo peor de todo es que le dice al operador que todo esta bien, y no le muestra el error, aclaro, yo guardo el mensaje de error en un archivo de texto, pero muestro un error personalizado en pantalla, y ese error personalizado no se ve...

Muchas gracias casimiro!!!

Saludos!!

guillotmarc 28-01-2010 10:14:42

Hola.

El mensaje de error es bastante claro, desde una transacción se intenta modificar un registro bloqueado por una modificación no confirmada en otra transacción aún activa.

Es un papelón, pero te toca revisar todo tu código, puesto que alguna transacción queda abierta. Recuerda que el conflicto no tiene porqué estar solo la tabla de stocks (aunque parece lo más lógico), puede ser cualquier tabla que intenten modificar ambas transacciones (como la de Logs, ...).

NOTA: Las transacciones tienen que ser lo más cortas posibles, abres la transacción, haces la modificación y la cierras enseguida. Por esto me gusta utilizar ClientDatasets, nunca tengo transacciones abiertas en mi programas, ni siquiera para mostrar datos en pantalla : abro la transacción, cargo el ClientDataset y cierro la transacción.

Saludos.

guillotmarc 28-01-2010 10:21:23

Por cierto, puedes probar una chapuza para salir del paso mientras lo arreglas bien.

Cambia el nivel de aislamiento de la transacción a READ UNCOMMITED (no estoy seguro de si Firebird acepta este nivel de aislamiento, pero como forma parte del estándar, puedes probar).

En este nivel de aislamiento no hay bloqueos, aunque una transacción no haya terminado sus cambios ya son visibles desde las otras transacciones. En cierta manera es como trabajar sin transacciones, lo cual evidentemente conlleva sus propios problemas.

Yo solo lo utilizaría como un parche temporal.


La franja horaria es GMT +2. Ahora son las 03:55:02.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi