PDA

Ver la Versión Completa : Desesperación Bloqueos


Rockin
10-11-2011, 17:17:27
Hola o nunca tengo problemas o los tengo todo seguidos.

Tengo problemas con los bloqueos de registros y no se por que. Tengo una aplicacion que recibe paquetes UDP para meter lineas en una centralita para hacer llamadas. Esta aplicacion cada vez que recibe un paquete lanza un SP en la BD que selecciona el registro que cumpla una serie de propiedades e inmediatamente despues lo actualiza marcandolo para no llamarlo, os paso el codigo:


SELECT FIRST 1 CAST(TELEFONO AS CHAR(9))
FROM MOVILES_POPUP
WHERE
ID_CAMPANIA = 'LEADS' AND PRIORIDAD = 1 AND (HORA_PROX_CONTACTO < CURRENT_TIME )
ORDER BY HORA_PROX_CONTACTO desc, FECHA_SOL_CLIENTE DESC,HORA_SOL_CLIENTE DESC, HORA_SOL_CLIENTE DESC,FECHA_PROX_CONTACTO DESC
INTO :TELEFONO_1;

UPDATE MOVILES_POPUP SET PRIORIDAD = 2,HORA_PROX_CONTACTO = CURRENT_TIME + 3600 WHERE TELEFONO = :TELEFONO_1;

suspend;


END;

Los paquetes se reciben cada segundo, que es tiempo suficiente para ejecutar el SP. Pero no se porque me sale el siguiente mensaje:
http://www.iccs.es/images/captura.png

Uso Firebird 2.5, FibPlus, he leido 300 manuales, he configurado la transaccion de mil maneras y nada. Estoy algo desesperado.

Si alguien tiene algo de luz que me ilumine.

guillotmarc
10-11-2011, 17:36:05
Hola.

Realiza las transacciones lo más cortas posibles. No dejes transacciones abiertas, cuando tengas que realizar uno de estos cambios, abre una nueva transacción, llama al procedimiento almacenado e inmediatamente después cierra la transacción.

Los conflictos de bloqueo solo ocurren cuando desde una transacción se intenta actualizar un registro modificado por otra transacción posterior a la apertura de la primera transacción. Si realizas las transacciones de la forma que te he dicho, la única probabilidad de colisión ocurre cuando dos estaciones intentan modificar el mismo registro durante las mismas milésimas de segundos. Vamos, prácticamente nunca (durante años programando así, apenas recuerdo haber encontrado nunca bloqueos).

NOTA: Esta es una de las razones por las que me encanta utilizar ClientDatasets, porqué con ellos no se dejan transacciones abiertas mientras el usuario consulta/modifica datos.

Saludos.

Rockin
10-11-2011, 18:12:51
Hola, estoy usando CDS, este está asociado a su DataSetProvider, este a su TTransaction y este a su DataSet.

En el evento AfterApplyUpdate del DataSetProvider, tengo lo siguiente:


if TContacto_leads.InTransaction then
begin
TContacto_leads.Commit;
end;


¿Donde debo abrir la nueva transaccion? ¿en el CDS? ¿en el servidor de capa intermedia? Estoy algo perdido.


Saludos

Lepe
10-11-2011, 19:24:56
La solución es gratuita, pero lleva tiempo. La tienes en los documentos de Interbase/Firebird (data definition guide, etc) en http://www.ibphoenix.com/resources/documents/general

Lo siento pero no hay magia, tus necesidades pueden ser diferentes a las mías, por eso no puedo aconsejarte. Si te fijas casi nadie pregunta ese tipo de cosas porque lee la documentación, se empapan de todo lo que necesitan entender, configurar, etc y en este foro solo se viene a preguntar por "ideas de procedimientos almacenados", trucos de SQL, de programación y tal.

Casimiro Notevi
10-11-2011, 19:40:58
Paisano, Rockin (http://www.clubdelphi.com/foros/member.php?u=26), aunque estés desesperado, pero recuerda poner un título descriptivo a tu pregunta. Gracias, amigo :)

guillotmarc
10-11-2011, 20:40:47
Hola, estoy usando CDS, este está asociado a su DataSetProvider, este a su TTransaction y este a su DataSet.

En el evento AfterApplyUpdate del DataSetProvider, tengo lo siguiente:

Código Delphi [-] (http://www.clubdelphi.com/foros/#)if TContacto_leads.InTransaction then begin TContacto_leads.Commit; end;


¿Donde debo abrir la nueva transaccion? ¿en el CDS? ¿en el servidor de capa intermedia? Estoy algo perdido.


Saludos

No es necesario ningún código de este tipo, puesto que el Provider del ClientDataset ya abre y cierra una transacción por si mismo.

Así que simplemente deja la transacción cerrada.

Naturalmente tienes más código. Primero porqué desde un CDS no puedes lanzar SP como el que comentas en el primer post, y segundo, porqué si te saltan bloqueos, es que estás manteniendo transacciones abiertas.

Si tienes todas las transacciones cerradas, no te puede saltar ningún error de bloqueo por abrir momentaneamente una transacción para realizar un cambio sobre un registro.

Recuerda, si te salta un bloqueo es porqué intentas modificar un registro desde una transacción que ha estado abierta desde antes que otra transacción haya modificado el mismo registro.

Revisa tu código, y cierra las transacciones que estás dejando abiertas. Cuanto menos tiempo queden abiertas, menos problemas tendrás.

Rockin
10-11-2011, 20:57:02
Perdon Casimiro Notevi.

Seguire probando y leyendo a ver si me aclaro, pero no lo veo, creo que está todo correcto. Algo se me está escapando.

Si guillotmarc , tengo más codigo el procedimiento lo llamo así:


with datDatosRemoto.CDSLeads do
begin
Close;
CommandText:= 'select telefono from SP_PEDIR_CONTACTO_LEADS';
Open;
Execute;

end;
:



El codigo que tengo puesto en el Provider lo vi en el libro la cara oculta de delphi 6. En el resto de transacciones ma va biem pero aqui al ser transacciones muy seguidas puede que me falle por eso. No se que hacer............

Casimiro Notevi
10-11-2011, 21:30:10
Es que, como dice guillotmarc, un deadlock sólo se produce cuando hay otra transacción abierta sobre el mismo registro, grabando. No importa las de lectura.
Así que sólo queda el que las revises, porque seguro que algo se te ha escapado por ahí.

guillotmarc
10-11-2011, 22:51:03
Hola.

... .... ... . En el resto de transacciones ma va biem pero aqui al ser transacciones muy seguidas puede que me falle por eso. No se que hacer............

Creo que ya te lo he insistido antes : No dejes transacciones abiertas y la posibilidad de bloqueos se vuelve prácticamente nula (solo pueden ocurrir cuando realmente se intente modificar el mismo registro en los mismos milisegundos).

Se te están quedando abiertas transacciones, y hasta que no lo corrijas seguirás teniendo problemas de bloqueos.

Puedes empezar verificando el estado de todas tus transacciones antes de lanzar esa modificación de registros (añade unas pocas líneas de código que te avisen si alguna de las transacciones está abierta en ese momento). Si es necesario también puedes utilizar las tablas de monitorización de Firebird para ver las transacciones que llevan más tiempo abiertas.

Ejemplo : http://www.firebirdfaq.org/faq352/

Mantener abiertas transacciones de lectura no es ningún problema, pero todas las escrituras deberían ejecutarse en el menor tiempo posible : abrir transacción, modificar registros y finalizar transacción inmediatamente. Es la única forma de evitar bloqueos, y es que es lógico que haya bloqueos cuando las transacciones se alargan, ¿ que se supone que debería hacer el motor de base de datos en estas situaciones ?, para respetar la integridad de los datos implicados en la transacción no tiene otro remedio que activar un deadlock (conflicto).

Saludos.

guillotmarc
10-11-2011, 23:11:04
Hola Casimiro.

Es que, como dice guillotmarc, un deadlock sólo se produce cuando hay otra transacción abierta sobre el mismo registro, grabando. No importa las de lectura.
Así que sólo queda el que las revises, porque seguro que algo se te ha escapado por ahí.

Otra posibilidad de deadlock es cuando tu misma transacción actual lleva demasiado tiempo abierta (incluso sin haber hecho aún la menor escritura).

Si una segunda transacción ha modificado entretanto un registro, aunque esa segunda transacción de modificación ya haya finalizado hace tiempo, tu no podrás volver a modificar el mismo registro dentro de la transacción actual. Puesto que tienes un conflicto entre la versión del registro que tienes en la transacción actual, y el registro real en la base de datos (que actualizó la segunda transacción, ya cerrada y finalizada).

No sé si me he sabido explicar :).

Por eso no me gustan los componentes como FibPlus, IBX, etc. ..., porqué prácticamente te obligan a mantener abiertas transacciones, y eso es una fuente segura de problemas.

Afortunadamente enlazarlos con ClientDatasets te solventa todos estos problemas, puesto que ya no necesitas dejar transacciones abiertas ni siquiera para lectura (que son las transacciones que se convertirán en problemáticas al querer pasarlas a transacciones de escritura cuando el usuario ha finalizado de trabajar con esos datos).

Las transacciones nunca se diseñaron para que estuvieran abiertas mientras el usuario trabaja con la información relacionada. Se supone que sirven solo para agrupar un conjunto de escrituras, y poder asegurar de que se hacen de forma conjunta (de forma que los datos sean coherentes a unas reglas de negocio).

Saludos.

Casimiro Notevi
10-11-2011, 23:30:43
Sí, se entiende.

Rockin
11-11-2011, 08:18:37
Hola , ante todo gracias por ayudarme y perdonadem si estoy dando mucho el coñazo.



Creo que ya te lo he insistido antes : No dejes transacciones abiertas y la posibilidad de bloqueos se vuelve prácticamente nula (solo pueden ocurrir cuando realmente se intente modificar el mismo registro en los mismos milisegundos).

Saludos.

No te enfades conmigo, guillotmarc, es que no se donde se queda la transaccion abierta o por que, es decir en el evento Execute del CDS tengo puesto CDS.ApplyUpDates(-1) y en el DataSset, he puesto la propiedad Autocommit a true. Teoricamente al realizar el commit, se cierra la transacción ¿no? ¿O me estoy equivocando en este concepto?. LLevo cuatro años con estos componentes y nunca me ha pasado este problema y ando muy perdido. Es una aplicacion Cliente-Servidor con 3 servidores de capa intermedia balanceados por carga.

guillotmarc
11-11-2011, 10:10:21
Hola.

Puedes empezar verificando el estado de todas tus transacciones antes de lanzar esa modificación de registros (añade unas pocas líneas de código que te avisen si alguna de las transacciones está abierta en ese momento). Si es necesario también puedes utilizar las tablas de monitorización de Firebird para ver las transacciones que llevan más tiempo abiertas.

Ejemplo : http://www.firebirdfaq.org/faq352/


¿ En que parte te pierdes ?.

Rockin
14-11-2011, 14:58:05
No se donde estoy fallando, teoricamente todas las transacciones se deben cerrar rapidamente. Le voy a poner un timeout al componente transaction a ver si así soluciono el tema. Lo he revisado todo mil veces.

Gracias y ya os contaré.

Saludos.

guillotmarc
14-11-2011, 17:36:33
Sí, yo siempre configuro mis transacciones con un timeout de 1 milisegundo (lo puedes hacer con toda seguridad, incluso aunque tus sentencias tarden más de 1 milisegundo en ejecutarse, puesto que este timeout solo se activa cuando la aplicación está en espera).

¿ Has verificado las transacciones más largas en curso ? (tal y como indica el artículo enlazado). Puede ser que el conflicto lo provoquen transacciones que ni siquiera sean de tu aplicación, sino conexiones de terceros a la misma base de datos.

¿ Has probado a añadir unas pocas líneas de código al actualizar, que te avisen de si algunas otras de tus transacciones están abiertas ?.

Saludos.