OT: Concurrencia en bases de datos Firebird o MariaDB

581 views
Skip to first unread message

Antonio Meza

unread,
Oct 17, 2014, 2:44:36 PM10/17/14
to publice...@googlegroups.com
Tengo dias investigando y leyendo sobre bloqueos y transacciones en Mysql, MariaDB y Firebird y ya logre que funcione como quiero pero no se si hay alguna otra forma mas optima, les cuento el problema y la solución que planteo para ver si alguien le ha sucedido y como lo ha solucionado. El procedimiento que escribo es para Firebird, pero es lo mismo para MariaDB lo que cambia es With LOCK (firebird) por FOR UPDATE (mariadb / mysql) y el SET Transaction para Mysql o Mariadb lo tengo así: para el update/delete/insert ISOLATION LEVEL READ COMMITTED y para los Select solo READ ONLY. Este código esta implementado en FoxyDB que estoy por liberar para el manejo de transacciones no para el problema que tengo.

Cabe mencionar que lo eh planteado en otro foro por si alguien que ve el otro foro luego me regañe por duplicarlo, pero hay muchos usuarios que no conocen el otro foro y a lo mejor me pueden dar ideas. les explicó

Tengo una tabla (puede ser cualquiera) por ejemplo CLIENTES, que es un catalogo, detallo como lo hago para ver de que forma lo resuelven ustedes.

UsuarioA, inicia transacción read only ...., hago un select a al cliente 1 llamado Juan, finalizo la transacción con un commit y el usuarioA ya tiene en pantalla en un formulario los datos del Cliente Juan

UsuarioB, inicia transacción read only ....., hago un select a al cliente 1 llamado Juan, finalizo la transacción con un commit y el usuarioB ya tiene en pantalla en un formulario los datos del Cliente Juan.

Resulta que el UsuarioA se fue a comer unos tacos al pastor, y el usuarioB hace cambios al registro modificando el nombre del cliente de JUAN a PEDRO, inicio una transacción READ WRITE ....., envió el UPDATE correspondiente y finalizo con un COMMIT. el usuarioB cierra la aplicación se va contento a comer.

Al rato regresa el usuarioA con dolor de panza porque comió muchos tacos, y en su pantalla tiene el registro del cliente 1 llamado todavía JUAN, le da editar y le pone el nombre MARÍA, le da guardar, entonces inicio una transacción READ WRITE ....., envió el UPDATE correspondiente y finalizo con un COMMIT. el usuarioA se va contento.

Pero al rato el usuarioB regresa consulta el registro e imprime y ve que aparece MARÍA, y se pregunta que paso?, porque si el usuarioA hubiera visto que ahora se llamaba MARÍA o que el sistema le hubiera informado que alguien hizo un cambio antes, ya el problema es interno y no del sistema.

Aquí el detalle es que incluso puedo hacer el primer SELECT y luego desconectarme del servidor y luego conectarme y enviar el UPDATE, por ello todo esta separado y una transacción no sabe que la otra hizo porque ya finalizo y se desconecto.

Explicación

Cuando el usuario busca un cliente me conecto al servidor, luego envió un "SET TRANSACTION READ ONLY SNAPSHOT WAIT, luego envió el SELECT para traer los datos del cliente y finalizo con un COMMIT y me desconecto del servidor, por lo tanto tiene en pantalla visualizando un registro.
Luego cuando el usuario va a guardar los cambios me conecto de nuevo e inicio un SET TRANSACTION READ WRITE READ COMMITTED WAIT, envió el UPDATE finalizo con un commit y desconecto del servidor, si no quiere guardar solo cierra el formulario. Por lo tanto en estos casos no hay transacciones activas que es lo recomendado e incluso conexión al servidor.

La nueva "solución" que estoy empleando es de nuevo usar un campo TimeStamp, pero ahora antes de enviar el UPDATE lo que hago es que envió un Select campoTimeStamp from clientes where id = 1 WITH LOCK , y luego verifico si la fecha es la misma y actualizo, si no es la misma entonces notifico al usuario que alguien mas modifico ese registro, de esta forma si un usuario dejo abierto el registro y lo modifica tendra un aviso, si dos usuarios al mismo tiempo intentan cambiar los datos de un mismo registro solo el primero le permitirá.

Detallo la solución:

Cuando el usuario busca un cliente me conecto al servidor, luego envió un "SET TRANSACTION READ ONLY SNAPSHOT WAIT, luego envió el SELECT y finalizo con un COMMIT y me desconecto del servidor.
Luego cuando el usuario va a guardar los cambios me conecto al servidor e inicio de nuevo con un SET TRANSACTION READ WRITE READ COMMITTED WAIT, pero ahora envió un Select campoTimeStamp from clientes where id = 1 WITH LOCK, verifico que la fecha sea igual y si lo es envió el UPDATE finalizo con un commit y desconecto del servido, si no es igual entonces aplico un Commit para finalizar la transacción porque no eh modificado nada, me desconecto del servidor y aviso al usuario que otro usuario hizo cambios al registro y le muestro los datos actuales.

Eh realizado pruebas y funciona perfecto, incluso si dos usuarios al mismo tiempo intentan guardar los cambios solo a uno le permitirá y al otro le enviara el mensaje, y el bloqueo dura unos milisegundos y solo afecta al registro actual y solo lo hago en cabeceras que son un solo registro, para nada lo haré con varios registros,

Que otra opción hay manejan ustedes?, cabe mencionar que el select with lock, lo hago a una búsqueda por el campo ID (Primary Key) por ello es super rápido y solo me traigo el campo timestamp que necesito la consulta esta optimizada.

saludos
Antonio Meza

José Luis

unread,
Oct 20, 2014, 9:19:54 AM10/20/14
to publice...@googlegroups.com
Hola Antonio Meza revisa esta respuesta en el siguiente http://yoforeo.com/firebird21/index.php?topic=94.0 

Julián May

unread,
Oct 20, 2014, 9:48:27 AM10/20/14
to publice...@googlegroups.com
Implementa una columna CheckSum  que tendrá una clave única y cuando haces un update verificas si ese CheckSum ah cambiado si ya cambio quiere decir que un usuario modifico en la RED. 

Cuando vas a modificar el  registro obtienes su clave de CheckSum 
haces las modificaciones y antes que grabes verificas ese CheckSum 

si es igual lo dejas grabar si no pues traes toda la información del usuario mandandole un mensaje que el registro ha sido modificado.


Cabe mencionar que sería en las tablas donde los registros constantemente cambien su valor, en una tabla de unidades no vendría el caso ya que la unidad no tendría que cambiar seguido.


Saludos.

Antonio Meza

unread,
Oct 20, 2014, 11:05:11 AM10/20/14
to publice...@googlegroups.com
Gracias Julian!!

Pero generar el CheckSum seria un paso adicional que ya obtengo con el campo TimeStamp.

saludos
Antonio Meza

Julián May

unread,
Oct 20, 2014, 6:00:37 PM10/20/14
to publice...@googlegroups.com
Sí no tendría caso ya sea puedes implementarlo con tu campo TimeStamp  o bien como te mencione siempre al final tendrás que generar un ID  unico al momento de insertar para grabarse en esa columna y luego verificarlo y cuando se modifique cambiarlo es casi la misma lógica. 


Saludos.

Carlos Miguel FARIAS

unread,
Oct 21, 2014, 6:50:10 AM10/21/14
to Grupo Fox
Si generas un id único con datos útiles, no solo obtienes un id (dentificador::pk de instancia de la entidad) si no que puede servirte como control de quien, cuando, donde metió los dedos. La misma función te sirve para calcular un valor (en lugar de un timestamp) con datos con alguna utilidad (el timestamp te indica cuando, pero no quien ni donde).
Saludos: Miguel, La Pampa (RA)

Antonio Meza

unread,
Oct 21, 2014, 2:59:27 PM10/21/14
to publice...@googlegroups.com
El ID lo genera la base de datos de forma automatica tambien, ese no es problema. de hecho cuando insertas un registro nuevo no hay problema, solo cuando modificas.

saludos

Antonio Meza

unread,
Oct 21, 2014, 3:02:00 PM10/21/14
to publice...@googlegroups.com
Creo entender a que te refieres con un campo Identificador, pero de igual forma es algo que tienes que generar manual, y me gusta usar lo automático y natural del motor de base de datos, ya que un identificador a diferencia de un Primary Key Autoincremental internamente el rendimiento es mayor en el segundo.

saludos

Carlos Miguel FARIAS

unread,
Oct 21, 2014, 6:42:23 PM10/21/14
to Grupo Fox
No puedo decir si un autoincremental en firefox u otros SGBD es más rápido que darle ya calculado el valor de clave primaria.
En vfp, un autoincremental "incrementa" el tiempo hasta en un 35%.
Lo que estoy indicando como solución es una columna que además de identificador, te permite saber quien cuando y donde (o desde donde) se solicito la creación del registro. Y además te sirve como clave primaria.
Y además te permite mezclar datos generados en diferentes motores de base de dato o distintos SGBD corriendo por separado.
O sea tenes el servidor A y le ingresan datos, tienes el servidor B e ingresan datos, luego puedes juntas las filas de ambos servidores y prácticamente sin conflicto.
Saludos: Miguel, La Pampa (RA)
Reply all
Reply to author
Forward
0 new messages