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)
-   -   Bloqueos tan superOptimistas que no me bloquean :( (https://www.clubdelphi.com/foros/showthread.php?t=12866)

Halfo 29-07-2004 19:13:09

Bloqueos tan superOptimistas que no me bloquean :(
 
Para situar un poco comentaré el entorno de trabajo:
BD: Firebird 1.5
Conectividad: IBX 6.01
RAD: Builder C++ 6
TIBTransaction = commit read_committed, rec_version, nowait

Ahora explicaré un poco más el problema:
Si no he entendido mal la filosofia de los "bloqueos" superoptimistas, más que un bloqueo es un conflicto normalmente a la hora de escribir en registros, no? O sea que si una transacción realiza una escritura en un campo de un registro y hace commit y una segunda transacción prueba a hacer lo mismo en el mismo campo del mismo registro deberia fallar y saltar el bloqueo optimista, no?
Yo entiendo que el ModifySQL de la segunda transacción si contiene en el WHERE todos los campos posibles de modificación no podrá actualizar por no encontrar registro alguno para modificar. Esto me parece quedar claro en este fragmento de la cara oculta:
Por supuesto, si alguien cambia cualquier dato del empleado 666, digamos que la extensión telefónica, la instrucción anterior no encontrará registro alguno y se producirá un fallo de bloqueo optimista.

Bueno, pues el problema es que no me salta ningun tipo de fallo de bloqueo ni nada. Yo pensaba que me saltaria alguna excepción como en el caso en que intentas repetir la clave primaria que si que falla el commit saltando una excepción. Pues no se si me esta fallando algo en la practica o no he entendido bien la teoria de los bloqueos optimistas.

En el caso del delete me pasa lo mismo me deja borrar un registro que ya habia sido borrado, aunque esto no es tan grave :D.
Pero vaya que me gustaria saber como funciona realmente el bloqueo optimista y poderlo usar, anque tambien he leido en el foro el 'simulacro' de bloqueo pesimista con un update inutil y tal pero me parece que tampoco solucionaria nada ya que la segunda transacción actua escribe o borra cuando la primera ya ha termindo (commit).

No se, alguien sabe como funciona todo esto realmente????

Gracias de antemano.

Mick 29-07-2004 22:33:17

Tal como lo has explicado , no debe saltar ningun tipo de error.
Si la primera transaccion finaliza (con un commit o un rollback) ANTES de que la segunda transaccion haga la modificacion al mismo registro, no debe saltar ningun tipo de error.
Esto es debido a que la primera transaccion ha finalizado, de modo que el registro que se haya modificado ya ha quedado desbloqueado, de modo que cualquier otra transaccion puede modificar el registro sin problema alguno.
Se produciria un error si la primera transaccion estuviese sin finalizar cuando la segunda intentase modificar el mismo registro.

Si funcionase como explicas no serviria para mucho el sistema, ya que en cuanto cualquier transaccion tocase algun registro y finalizase, ese registro daria siempre error al intentar ser modificado posteriormente, lo que no tendria de mucha utilidad, no serviria para nada una base de datos que solo permitiese modificar los registros una sola vez y despues diesen siempre error.

Saludos

Halfo 30-07-2004 02:49:51

A ver si me explico mejor:
Parte de lo que dice, Mick, lo entiendo perdectamente ya que si la segunda transacción no bloquea de forma pesimista con un lock, select for update o update inutil el registro,es normal que la primera transacción puede acceder al registro, modificarlo, comiterarlo y no encontrar problema alguno, luego la segunda transacción cuando quiera modificar (update) el mismo registro ya no actuará concurrentemente con la primera transacción que ya terminó.

Peró insisto que en este punto hay un problema. Según lo que creo haber entendido en "la cara oculta de C++" del señor Marteens, la modificación del registro realizada por la segunda transacción, si se realiza utilizando en la clausula WHERE todos los campos posibles de modificar (no solo la clave primaria, aunque en algunos casos esta tambien pueda cambiarse) resulta que la ejecución de la sentencia ModifySQL intenta un update sobre un registro que no encuentra, por lo que no puede realizar tal modificación, ahí es donde esta la anomalia.
Lanzando dicha sentencia SQL (update ....where ...) desde una utilidad SQL aparte se puede comprobar que la sentencia no afecta a ningun registro y devuelve:

This command did not return data, and it did not return any rows

mientras que si existiera el registro se obtendría:

1 Row(s) affected

YO ME PREGUNTO, ¿no es importante saber si realmente has podido realizar el update o no? los componentes IBX no informan de ninguna forma que la sentencia ha fallado, es decir no ha afectado a ninguna fila???

¿Me estoy equibocando en algo?¿la situación que planteo no es lo más normal si no se usan bloqueos pesimistas? de hecho el bloqueo optimista no se basa en esto: que todo el mundo pueda ir modificandolo todo hasta que salte un problema de este tipo?

Otra vez, gracias por la atención.

jachguate 30-07-2004 09:39:54

Cita:

Empezado por Halfo
Peró insisto que en este punto hay un problema. Según lo que creo haber entendido en "la cara oculta de C++" del señor Marteens
...
los componentes IBX

El libro "La cara oculta de C++", al menos el que yo leí... hacia referencia a los componentes de acceso via BDE, y no a IBX, por lo que la referencia no necesariamente es válida.

De hecho, el comportamiento puede cambiarse con la propiedad UpdateMode, introducida en la clase TDBDataSet (del BDE), de upWhereAll, a upWhereChanged o upWhereOnly.

En el caso de las IBX, según recuerdo, las sentencias SQL generadas automáticamente para actualizar los registros en un TIBUpdateSQL, en el caso de insert y update comprenden solamente la llave primaria.

En cualquier caso, podrias modificar el comportamiento por defecto sobreescribiendo estas sentencias para incluir cualquier campo que sea de tu interes (incluso todos).

Me parece poco probable que los componentes dejen pasar por alto el hecho de que no se actualizara ningún registro en la BD, pero no me considero experto en el tema ni dispongo actualmente del tiempo para probarlo por mi mismo. Por lo tanto, dejo la idea, espero que vos hagas pruebas y nos saques de una buena vez de la duda.

Hasta luego.

;)

guillotmarc 30-07-2004 11:23:52

Hola.

Puedes utilizar un ClientDataset para modificar los registros. Conectas tu IBQuery a un DatasetProvider y este a un ClientDataset. Cuando quieras hacer modificaciones las haces en el ClientDataset, y para pasar los cambios a la Base de Datos llamas al ApplyUpdates.

La ventaja es que puedes usar las opciones upWhereAll, upWhereChanged, upWhereKeyOnly que comentaba Juan Antonio (se configura en el DatasetProvider). Esto hace que se ejecute una instrucción distinta en función de la opción seleccionada, incluyendo solo la clave primaria en la sección Where, o bien la Clave primaria más los campos que se van a modificar y finalmente todos los campos.

NOTA: Te recomiendo utilizar upWhereChanged. Que solo te va a provocar un error si intentas modificar un campo que ya ha sido modificado por otro usuario.

Saludos.

Halfo 30-07-2004 14:09:19

Siento volver a insistir, pero no se si consigo hacerme entender y transmitir mi duda, ya que todo el mundo acaba contestandome algo que ya sabia y que NO resuelve mi duda.

Respecto las dos ultimas contestaciones de jachguate y guillotmarc:
He hecho referencia al libro "La cara oculta de C++" porque es la unica lectura minimamente extensa y completa que tengo respecto al desarrollo de aplicaciones orientadas a BBDD en entornos RAD de Borland, ya se que esta un poco anticuado, pero todas las demas lecturas realizadas al respecto (Firebird/interbase,IBX,...) son documentos mucho más concretos o demasido generales y raramente hacen referencia a una metodologia consistente para el desarrollo. Por lo que mi base de conocimiento es un viejo libro + pequeñas ideas extraidas de manuales,articulos y respuestas del foro (si alguien tiene una buena recomendación de lectura que no se calle). En el libro "la cara oculta" se describen las actualizaciones optimistas como aquellas en que a la hora de editar los registros no se bloquean, se permite la edición concurrente y los problemas los tendrán los que intenten actualizar en segundo lugar ya que no encontraran el registro que estaban editando. Esto entiendo cuando leo:

Las dos aplicaciones pueden realizar las asignaciones al buffer de registro sin ningún tipo de problemas. Recuerde que este buffer reside en el ordenador cliente. La primera de ellas en terminar puede enviar sin mayores dificultades la petición de actualización al servidor. Sin embargo, cuando la segunda intenta hacer lo mismo, descubre que el registro que había leído originalmente ha desaparecido, y en ese momento se aborta
la operación mediante una excepción.


Pero el libro esta hablando de una tabla de del BDE y por eso menciona la propiedad UpdateMode donde especificar la forma de localizar el registro al actualizar. El libro tambien detalla lo que hace el BDE en realidad que no es mas que realizar un update con el WHERE para localizar el registro incluyendo la pKey o lo cambiado o todos los campos.
Bueno como el BDE esta anticuado y es muy 'pesado' , para conectarse a Interbase/Firebird actualemente lo mejor es utilizar IBX (o otros componentes directos IBO,IBPlus,...) y segun tengo entendido los componentes TIBTable, TIBQuery , TIBUpdateSQL existen por compatibilidad con el pasado y se debe usar TIBDataSet o TIBSQL. Luego el TIBDataSet nos oferece la posibilidad de configurar a nuestro antojo como actualizar nuestro dataser con ModifySQL por lo que podemos poner la misma sentencia SQL que pone el UpdateMode en el caso del BDE. Hasta aquí todo muy bien pero.....
El UPDATE FALLA y los componentes no me avisan!!!!!
He monitorizado con TIBSQLMonitor lo que esta pasando en el post:
Se realiza un update + un select + un fetch del registro.
En caso que no haya problema (no han modificado el registro) todo ok.
pero si observo el caso en que debería fallar el update obserbo:
Se realiza un update + un select + un fetch del registro + un PEQUEÑISIMO
SEOFReached. que supongo es el mensaje que da al realizar el fetch y no encontrar datos ,(curioso que del update no diga nada pero bueno)

No se si veis donde quiero llegar, intento realizar lo que yo entiendo como un control optimista de la concurrencia pero no puedo ya que no encuentro la forma de que se me avise que esta fallando algo (solo estoy exponiendo el caso del update, con el delete tambien pasa lo mismo, por suerte el insert no tiene esta problematica :D ).

A) ¿El planteamiento del control optimista es erronio?
B) ¿La implementación con estos componentes IBX es erronia?
C) ¿Me estoy dejando algo, y por eso no me saltan los fallos?
D) Ninguna de las anteriores.

Guillotmarc, de momento no quiero complicar más el tema con CachedUpdates y ApplyUpdates, que si utilizaré para los datos con master/detail, etc...

guillotmarc 30-07-2004 17:11:06

Hola.

Lamentablemente tu duda no te la puedo resolver. Simplemente es que estamos hablando de componentes BDE y IBX, y nunca he utilizado ninguno de ellos.

Solo he pretendido ayudarte, aconsejándote el uso de unos componentes que si conozco (los ClientDatasets).

NOTA: Utilizar un control optimista, me parece la forma más correcta de atacar una base de datos. Aunque como ya te he comentado, no puedo decirte que es lo que haces mal con IBX.

NOTA 2: El uso de Clientdatasets no tiene nada que ver con el modo CachedUpdates, aunque el concepto sea parecido.

Saludos.


La franja horaria es GMT +2. Ahora son las 03:48:06.

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