donweb dattatec clientes cliente delphi firebird interbase dbexpress

delphi - dattatec - Cómo hacer que la aplicación de cliente Firebird espere una fila para desbloquear



dattatec panel de clientes (3)

El cliente puede especificar si la transacción debe esperar una resolución de interbloqueo. Si, en su caso, el interbloqueo se produce de inmediato, probablemente se deba a su configuración (utilizando el parámetro de transacción nowait en el cliente). No usar nowait hará que el servidor detecte un interbloqueo y (después de un tiempo de espera configurable) generará una excepción en el cliente.

Desde Firebird 2.0 , también puede especificar un tiempo de espera de bloqueo en una transacción del cliente, anulando el valor de tiempo de espera configurado por el servidor.

Mi familiaridad es con el mundo del servidor Microsoft SQL usando ADO (dbGo), y he escrito muchas aplicaciones para ese entorno. Ahora tengo una aplicación Delphi 7 heredada con una base de datos Firebird 2.5 que debo mantener.

PERO estoy encontrando que si 2 aplicaciones cliente ejecutan esto:

SQLQuery.SQL.Text := ''Update mytable set field1 = 11 where keyfield = 99'' SQLQuery.Execute;

casi exactamente al mismo tiempo, la segunda aplicación recibe un error de "interbloqueo" inmediatamente. En SQL Server, habría un período de espera

ADOConnection.Isolationlevel = ilCursorstability; ADOConnection.CommandTimeout := 5;

antes de que se levante cualquier excepción en la segunda aplicación cliente. El manejo de excepciones podría implicar una reversión en lo que se consideraría como una situación muy inusual dentro de un proceso por lotes. Esto es razonable . 5 segundos es un tiempo muy largo en el procesamiento de la computadora.

Ahora, mis intentos de usar la misma metodología en el Cliente Firebird han sido infructuosos porque el "punto muerto" (en realidad, un registro en uso) ocurre de inmediato.

Si el motor de la base de datos no se puede configurar para esperar un poco a que mejoren las condiciones (para que se liberen los bloqueos de registros), la responsabilidad ahora debe recaer en el desarrollador de la aplicación cliente, que debe escribir código increíblemente lento para superar lo que me parece importante. Falla de Firebird.

Una vez que se ha detectado el "interbloqueo", la condición no se borra, excepto desconectando el componente de conexión

while rowsupdated = 0 and counter < 5 do begin try rowsupdated := SQLQuery.Execute; except SQLConnection.Connected := False; SQLConnection.Connected := True; end; Inc(Counter) end;

¿Cómo se crean clientes robustos para la actualización de tablas de múltiples usuarios cuando no tiene una tolerancia de bloqueo sustancial en Firebird, utilizando DBX en Delphi?


Estoy haciendo uso del botón "responder a su propia pregunta". He descubierto una solución.

  1. Instale el controlador ODBC de código abierto IBPhoenix para Firebird / Interbase
  2. Configure ODBC DSN para conectarse a Firebird.fdb con nowait marcado y LockTimeout configurado en segundos. Elegí 15 segundos.
  3. Use Delphi 7 ADO (dbGo) TADOConnection configurado para usar el proveedor Microsoft OLE DB para los controladores ODBC.
  4. Este es el bit importante: establezca ADOConnection.TransactionIsolation en ilReadUncommited o ilDirtyRead.

Lo que esto hace es que el TADOQuery.ExecSQL realmente espere (hasta los 15 segundos especificados) si encuentra que el registro ya se ha actualizado en una transacción que aún no se ha confirmado o revertido.

Esto es diferente al controlador DBX que inmediatamente provoca una excepción llamada "interbloqueo" en esta situación. (como hemos discutido anteriormente)

Entonces, si ambas consultas hacen esto

Update MYTABLE set NUM = NUM + 1 where keyvalue = 99;

y el valor de inicio (antes de cualquier actualización) es 0, el valor de NUM después de que ambas transacciones se hayan comprometido es 2, como se esperaba.

Comenzando de nuevo con NUM = 0. Si la primera transacción se retrotrae, la segunda transacción puede confirmarse (o retrotraerse). Y el valor después de que se haya comprometido la segunda actualización, es solo 1.

No sé cómo o por qué esto funciona tan bien, especialmente porque se supone que Firebird no es compatible con ReadUnComitted o DirtyRead, pero estoy feliz de que funciona de la manera que quiero.


La transacción de Firebird se puede configurar para que sea ya sea nowait o wait (con o sin un tiempo de espera específico). La forma en que se puede configurar depende del controlador y, como no estoy familiarizado con Delphi, no puedo hacer comentarios al respecto. Nowait suele ser el predeterminado, ya que en la mayoría de los casos, esperar solo retrasará lo inevitable.

El error de "interbloqueo" es un poco inapropiado, ya que no es un interbloqueo en la lengua vernácula de concurrencia normal. La segunda parte del error suele ser más descriptiva, por ejemplo, la actualización entra en conflicto con la actualización simultánea. , es un artefacto histórico que se agrupa en "punto muerto" (aunque en la mayoría de los casos, estos errores significan que necesita reiniciar su transacción, por lo que en ese sentido está "muerto").