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)
-   -   Escritura simultanea en una tabla (https://www.clubdelphi.com/foros/showthread.php?t=61233)

Esteban Quito 30-10-2008 22:22:30

Escritura simultanea en una tabla
 
Hola gente.
Como dice el título, tengo problemas al escribir en la misma tabla desde dos PCs distintas, pero los usuarios no me pudieron precisar si es a su vez sobre el mismo registro. Además, les sucede en un bajísimo porcentaje de veces. Tan bajo que en el lugar de desarrollo no he podido reproducir el error ninguna vez.

El caso es el siguiente. Las aplicaciones de Insumos se registran en una tabla. De ésta, depende otra que almacena los productos y cantidades aplicadas. Cuando se guarda una aplicación, se recorre la segunda tabla para modificar el stock de insumos que está en una tercera tabla. De este modo, existe la posibilidad que desde dos puestos de trabajo se intente escribir en el mismo registro de stock.

Mis preguntas en definitiva es: Existe alguna restricción o parámetro de los dataset o Firebird que no haya previsto? Es Firebird el encargado de controlar la recurrencia de datos o se debe controlar desde programa?
Uso SQLConecttion, SQLDataSet, DataSetProvider, ClienteDataSet. No uso transacciones.

Muchas gracias y si llegara a ser una tontera, sepan disculpar.

RolphyReyes 30-10-2008 22:38:53

Saludos.

No especificas como haces los UPDATE o INSERT de las tablas en cuestión.

Pero una opción podría ser utilizar Stored Procedure y Trigger para agilizar estas operaciones.

Otra opción no muy recomendada (según tengo entendido) es usar la sentencia With Lock o For Update.

Extraído de Firebird V1.5 Release Notes:
Cita:

(1.5) Bloqueos explícitos
Nickolay Samofatov
La introducción de la cláusula opcional WITH LOCK proporciona una limitada capacidad de hacer bloqueos pesimistas explícitos para uso prudente en las condiciones en las que el conjunto de registros afectados es a) extremadamente pequeño (mejor si es uno solo) y b) exactamente controlado por el código del aplicativo.

NOTA La necesidad de un bloqueo pesimista en Firebird es muy rara de hecho y debe ser bien
entendido antes de plantearse utilizar esta extensión.
Sintaxis
SELECT ... FROM <algunatabla>
[WHERE ...]
[FOR UPDATE [OF ...]]
[WITH LOCK]
...;
Si la cláusula WITH LOCK se ejecuta bien, se realizará un bloqueo de los registros seleccionados y se
evitará que cualquier otra transacción obtenga acceso de escritura a dichos registros, o sus
dependientes, hasta que su transacción termine.
Si se incluye la cláusula FOR UPDATE, el bloqueo se aplicará a cada registro, uno por uno, guardándose
en la caché del servidor. Llega a ser posible, entonces, que un bloqueo que pareció funcionar cuando
fue solicitado sin embargo falle posteriormente, cuando se intenta enviar un registro que está
bloqueado por otra transacción.
Es esencial comprender los efectos del nivel de aislamiento de las transacciones y otros atributos de las
mismas antes de intentar incluir bloqueos explícitos en las aplicaciones.
La construcción SELECT... WITH LOCK está disponible en DSQL y PSQL. Sólo funciona en el nivel más
alto, con sentencias SELECT que afectan a una única tabla. No está disponible en subconsultas, ni para
joins. No se puede especificar con el operador DISTINCT, la cláusula GROUP BY o cualquier otra
operación de agregación de registros. No puede utilizarse con o en una vista, ni con tablas externas, ni
con los resultados de un procedimiento almacenado llamado desde un select.
Comprendiendo la cláusula WITH LOCK
Como el motor considera, por turnos, cada registro que cae bajo una sentencia de bloqueo explícita,
bien devuelve la versión del registro que ha sido confirmada lo más actualmente posible, sin importar
el estado de la base de datos cuando la sentencia fue enviada, o bien devuelve una excepción.
El comportamiento esperado y la notificación de conflictos depende de los parámetros especificados a la transacción (modo TPB).

Ejemplos
i) (simple)
SELECT * FROM DOCUMENT WHERE ID=? WITH LOCK
ii) (varios registros, procesados uno a uno por un cursor DSQL)
SELECT * FROM DOCUMENT WHERE PARENT_ID=? FOR UPDATE WITH LOCK
Hasta luego.

rastafarey 03-11-2008 21:51:28

Resp
 
Esto se conoce como el famoso abrazo mortal.

Y hasta tengo entendido esto solo puede pasar si el nivel de isalacion no incluyen el read version(configuracion de la transaccion).

De lo contrario jamas deberia pasar esto.

Esteban Quito 03-11-2008 22:40:11

Este es el código que guarda en una de las tablas en cuestion. En la que yo supongo que pueden estar escribiendo simultaneamete en el mismo registro dos PCs.

Código:

  CDInsumosAplicados.First;
  while not CDInsumosAplicados.Eof do
  begin
    CDStockInsumos.Locate('ARTICULO_ARC',CDInsumosAplicadosPRODUCTO_RRA.AsString,[loCaseInsensitive]);
    if CDStockInsumosARTICULO_ARC.Value=CDInsumosAplicadosPRODUCTO_RRA.Value then
    begin
      CDStockInsumos.Edit;
      CDStockInsumosSTOCK_STC.AsCurrency:=CDStockInsumosSTOCK_STC.AsCurrency
                                          -(CDInsumosAplicadosCantidadusada_RRA.AsCurrency
                                            *CDInsumosAplicadosIndiceunidad_ART.AsCurrency);
    end;
    {Sino Existe Relacion con el articulo}
    {Fin-Sino Existe Relacion con el Articulo}
    CDInsumosAplicados.Next;
  end;
  CDStockInsumos.ApplyUpdates(0);
  CDStockInsumos.Refresh;

Perdón por insistir con lo mismo. ¿Estoy equivoado al pensar que el encargado de controlar la escritura en un mismo registro es del propio Firebird y no el codigo de la aplicación?
Si es necesario que diga cómo están parametrizado los controles que uso para acceder a los datos, me dicen.

rastafarey 04-11-2008 15:52:05

Resp
 
El problema no se basa en como ni con que aplicacion escribes los datos es de como este configurada el nivel de isolasion osea como se configure la tranasaccion.

Una configuracion que evita el abrazo mortal (dead lock) es:

isc_tpb_read_committed
isc_tpb_rec_version
isc_tpb_nowait

Lo de los bloqueos explicitos te lo soluciona perfecto pero si sabes con presicion lo que estas haciendo te va a causar mas dolores de cabeza que lo que te va a solucionar.


La franja horaria es GMT +2. Ahora son las 05:50:21.

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