PDA

Ver la Versión Completa : Problema en el uso de Transacciones


AGAG4
08-06-2005, 16:27:04
Tengo un problema con el uso de Transacciones en mi Aplicación, lo que pasa es que relación Maestro Detalle (Factura), mi problema se centra en que por cada Artículo que registran en la Factura automaticamente por medio de un trigger lo inserto en otra tabla de Saldos de Artículos, hasta aqui vamos bien, pero si en otra Pc intentan también Facturar el mismo artículo al mismo tiempo, me marca Error "Conflict on no wait deadlock transaction" este error es debido a que intentan accesar al mismo registro que es cuando el trigger quiere modificar el saldo de dicho artículo, el modo de aislamiento que uso en las transacciones es la siguiente:
read_committed
rec_version
nowait
Uso los componentes IBX 6.08 con Delphi 6.0 y FireBird 1.52 Es una Aplicación de 2 Capas Cliente Servidor, este problema lo solucione con aplicar un CommitRetaining cada vez de que inserto un Artículo al Detalle de la Factura, pero me voy a enfrentar a otro problema que es cuando intentan a modificar una Factura que este Registrada, y si quieren modificar el Detalle de esta misma después que la modifiquen decide el usuario Cancelar Cambios, no me va a funcionar el RollBack porque se estará usando el commitretaining.

Que estaré haciendo mal????

El Nivel de Aislamiento en las Transacciones es el correcto????

A Alguien ya le ha sucedido eso, y como lo resolvio????

Será que tengo que quitar el trigger y aplicar los Movimientos a la Tabla de Saldos al final de la captura de la Factura por medio de un Procedimiento Almacenado?????

Que tenga buen día.

AGAG4
09-06-2005, 16:01:59
Ya los probe con los componentes FibPlus y es la misma....

jachguate
09-06-2005, 17:39:46
Te sugiero evaluar el uso de actualizaciones en cache (cachedupdates). Esto hará que los cambios aplicados por el usuario a los datasets sean almacenados en memoria hasta que llames a applyUpdates, logrando que la duración de la transacción sea mínima, sin perder la capacidad de dar marcha atras si el usuario se arrepiente (CancelUpdates)

Hasta luego.

;)

AGAG4
10-06-2005, 16:54:15
Entonces la Transacción empieza cuando aplico un applyUpdates????

Agradezco sus comentarios....

vtdeleon
10-06-2005, 17:34:36
Saludos.Entonces la Transacción empieza cuando aplico un applyUpdates????

Agradezco sus comentarios.... Debes tener (En el dataset que uses) la propiedad CacheUpdate en True, Si quieres guardar los datos en memoria en la tabla usas AppyUpdate, sino CancelUpdate. La ayuda de delphi puede guiarte un poco

jachguate
10-06-2005, 17:39:03
Entonces la Transacción empieza cuando aplico un applyUpdates????

Agradezco sus comentarios....


La transacción inicia cuando haces un select, pero es una transacción de solo lectura que no afecta a nadie. Esta transacción será promovida a una de lectura/escritura cuando llamas a apply updates.. que aún con cientos de actualizaciones tardará solo unos instantes, ya que inmediatamente después haras commit, y asunto olvidado.

Entonces la contención y la posibilidad de deadlocks es reducida en gran cantidad.. .aún cuando sigue siendo posible que dos clientes colisionen... es mucho menor en entornos con pocos usuarios. Y entonces podes dejar las transacciones en modo wait, puesto que la espera será realmente corta.

Hasta luego.

;)

AGAG4
11-06-2005, 00:18:36
Muchísimas gracias por sus comentarios son muy valiosos, hare lo que me recomiendan....

Que tengan Muy Buen Día....

Saludos....

AGAG4
13-06-2005, 23:21:03
Con respecto al Guardado en la Cache del ibDataset, el problema que tengo ahora, es que en la llave primaria del Detalle es Serie+Folio+Indice, donde indice es un consecutivo, donde cada vez de que se inserte un nuevo registro va tomando el Siguiente, esto lo hacia por medio de un Procedimiento Almacenado, pero ahora que no se va a la BD si no a la Cache quize hacer la prueba del cual muestro a continuación:

....
var
Marca:TBookMark;
eve:TDataSetNotifyEvent;
begin
with dmFactBabatsa do begin
BookMarkDFAC:=true;
if tDFacturas.RecordCount<1 then
result:=1
else begin
try
eve:=tDFacturas.BeforePost;
tDFacturas.BeforePost:=Nil;
Marca:=tDFacturas.GetBookMark;
tDFacturas.DisableControls;
{Empieza la Acción....}
{AQUI MARCA ERROR, ES DECIR LLAMA AL EVENTO BEFORE POST}
{E INTENTA HACER EL POST Y MARCA ERROR EN CAMPO INDICE QUE LLAVE}
{PRIMARIA ESTA INCOMPLETA, AUN ASI ENTRA AL EVENTO AUNQUE }
{ANTERIORMENTE LE HAYA PASADO EL VALOR NIL}
tDFacturas.First;

while not tDFacturas.Eof do begin
result:=tDFacturasINDICE.value+1;
tDFacturas.Next;
end;
{Finaliza la Acción....}
tDFacturas.GotoBookMark(Marca);
{Tomar Posición Original}
tDFacturas.EnableControls;
tDFacturas.BeforePost:=Eve;
finally
tDFacturas.FreeBookmark(Marca);
end;
end;
BookMarkDFAC:=false;
end;


Sugerencias para Tomar Totales de Factura ó Tomar el Indice Consecutivo dentro de la Cache????

Agredezco cualquier sugerencia.

AGAG4
14-06-2005, 03:18:01
Otra Cosa Juan Antonio porque menciona esto....

"es mucho menor en entornos con pocos usuarios."

El método de uso de Cache no funciona como debiera con muchos Usuarios accesando al mismo tiempo en una Base de Datos????

Es la otra duda que me quedo respecto a sus comentarios....

Que Tenga Buen Día....

AGAG4
14-06-2005, 16:01:33
No tuve más remedio que lidiarme con un DBF Físico, le añadí los campos que ocupo para determinar el INDICE de la llave primaria y para los TOTALES de la Factura y me funcionó, no encontre nada como crear una tabla en memoría y lidear con ella....

Saludos.

jachguate
14-06-2005, 17:01:56
Hola.

Otra Cosa Juan Antonio porque menciona esto....

"es mucho menor en entornos con pocos usuarios."

El método de uso de Cache no funciona como debiera con muchos Usuarios accesando al mismo tiempo en una Base de Datos????


Lo que yo dije fué:

Entonces la contención y la posibilidad de deadlocks es reducida en gran cantidad.. .aún cuando sigue siendo posible que dos clientes colisionen... es mucho menor en entornos con pocos usuarios. Y entonces podes dejar las transacciones en modo wait, puesto que la espera será realmente corta.

Me refiero a que la probabilidad de que ocurran deadlocks o problemas de concurrencia (contención) es tan baja en entornos con pocos usuarios, que al usar este método podes olvidarte de ella. En cambio, en entornos con muchos usuarios esta probabilidad va subiendo de manera que tendrias que programar algo para lidiar con ella.

Imagina un entorno donde las transacciones que tardan 0.1 segundos, gracias al uso de actualizaciones en cache. Nos pondremos en el escenario de un supermercado con 200 cajeros y que en un momento particular todos venden cocacola y panecillos (que están en oferta). Aún cuando las transacciones son realmente cortas, la probabilidad de que dos cajeros finalicen una factura al mismo tiempo, y que esta tenga que afectar la existencia de un mismo artículo es ya importante... quizas una vez a la semana, talvez hasta una vez por hora. Entonces habrá que hacer algo para interceptar el error y lidiar con él.. p. ej. hacer esperar a uno de los dos cajeros medio segundo y reintentar la operación.

Hasta luego.

;)

pd. Es buena idea que edites el mensaje que obliga a que sea necesario correrse a la derecha para poder escribir esto.... es realmente molesto.

AGAG4
15-06-2005, 19:44:24
De hecho es lo que hice con las Transacciones al Finalizar la Factura hice un ciclo que pongo a la vista si alguien más le sirva:

while true do
try
if Detalle.UpdatesPending Then
Detalle.ApplyUpdates;
if Maestro.UpdatesPending Then
Maestro.ApplyUpdates;
break;
except
//Si Hay Bloqueo en Registro ReIntentar de Nuevo....
on E:Exception do
if UpperCase(copy(e.message,1,15))<>'DEADLOCK UPDATE' then
break;
end;


En cuanto al Editar el Mensaje en el Foro la verdad no se cual fue la causa de que el mensaje salga TAN ANCHO, me comenta que tengo que EDITARLO, como se hace eso????, porque cuando yo quiero agregar un NUEVO COMENTARIO solo presiono el boton RESPONDER y Disculpa por esta Molestia....

Gracias por sus comentarios....
Que Tenga Buen Día....

jachguate
15-06-2005, 19:50:16
Bueno... este último mensaje lo has editado.. poniendo como razón la palabra "corrección".

¿Estas seguro que no sabes como editar mensajes?

Lo que hace muy ancho el mensaje es el comentario, que está puesto en una sola línea... la etiqueta delphi, sql y code no ajustan el texto al ancho de la ventana... hacen que la ventana sea tan ancha como la línea mas larga de texto. Quizas sea dificil de ver en el editor (que si quiebra las líneas) pero es fácil de identificar aqui mismo... es la única línea que llega hasta el final (dentro del código) en este mensaje (http://www.clubdelphi.com/foros/showpost.php?p=92387&postcount=8)

Hasta luego.

;)

AGAG4
15-06-2005, 19:56:49
Mucho Mejor.... Gracias.

Que Tenga Buen Día.