Controlar modificaciones en registros (MySQL,MariaDB)

1,514 views
Skip to first unread message

Francisco

unread,
Jul 20, 2015, 5:46:13 AM7/20/15
to publice...@googlegroups.com
Buenas, estoy migrando a MariaDB y no se muy bien como controlar el tema de las modificaciones en los registros de las tablas. Me refiero que yo me gusta que dos usuarios puedan acceder a modificar el mismo registro sea cual sea la tabla. En Fox lo hacia mediante el rlock(). Ahora se me ocurre tener una tabla auxiliar de bloqueos donde tenga el nombre de la tabla y el id del registro modificado pudiendo hacer una gestión de la misma obviamente con bloqueos para escrituras y borrados sobre dicha tabla de bloqueos o quizá exista otra manera más eficiente para este proposito?

pd: Uso FoxyDB para acceder a MariaDB(Mysql)

Carlos Miguel FARIAS

unread,
Jul 20, 2015, 7:09:06 AM7/20/15
to Grupo Fox
Consulta:
https://mariadb.com/kb/es/
Lo que preguntas, lo vi en brasilero.
Saludos: Miguel, La Pampa (RA)

Francisco

unread,
Jul 20, 2015, 7:11:27 AM7/20/15
to publice...@googlegroups.com, carlosmig...@gmail.com
Donde? Puedes poner el link...

Francisco

unread,
Jul 20, 2015, 7:25:34 AM7/20/15
to publice...@googlegroups.com, dire...@informatica-apliges.com, carlosmig...@gmail.com
Bueno he entrado esto: https://groups.google.com/forum/#!topic/publicesvfoxpro/2ybBgckbUQk
voy a mirarlo un rato... la clave es la palabra "concurrencia" para que en san google salga correctamente...

Programas ToP S.A.S.

unread,
Jul 20, 2015, 7:38:32 AM7/20/15
to publice...@googlegroups.com

En MySQL y creo que en todas las BD el motor lo hace solo si utilizas START TRANSACTION......COMMIT/ROLLBACK y en medio las operaciones sobre las tablas.

Francisco

unread,
Jul 20, 2015, 7:52:33 AM7/20/15
to publice...@googlegroups.com, progra...@gmail.com
Si eso lo tengo claro, ninguno de los 2 que están modificando van a entrar en conflicto. Lo que quiero es que si un usuario "Edita" un registro (Y pongo Edita entre comillas pq eso para nada existe en ninguna BBDD como Mysql, MariaDB etc...) me refiero a la acción de pulsar Editar en un formulario con la intención de realizar cambios en el mismo. A los demás usuarios les informe que ese registro está siendo "Editado" (Modificado) por otro y así no llevar a problemas del tipo "....el ultimo que guarda....". Veo que hay varias formas ya discutidas pero me gustaría implentar este tema de forma correcta.

Gracias.

Francisco

unread,
Jul 20, 2015, 7:59:16 AM7/20/15
to publice...@googlegroups.com, dire...@informatica-apliges.com, progra...@gmail.com
En este artículo he encontrado algo relativo al Timestamp y como utilizarlo para realizar este chequeo, creo que es una buena idea:

Carlos Salcedo

unread,
Jul 20, 2015, 8:38:46 AM7/20/15
to visual fox, progra...@gmail.com
Aca te dejo en enlace con un trigger para controlar lo que tu necesitas con una tabla
de auditoria



Saludos
Carlos


Date: Mon, 20 Jul 2015 04:52:33 -0700
From: dire...@informatica-apliges.com
To: publice...@googlegroups.com; progra...@gmail.com
Subject: Re: [vfp] Controlar modificaciones en registros (MySQL,MariaDB)

Antonio Meza

unread,
Jul 20, 2015, 2:11:25 PM7/20/15
to publice...@googlegroups.com, dire...@informatica-apliges.com, progra...@gmail.com
Hola Francisco!!

No uses el campo TimeStamp ya no uso esa solución, porque requieres de muchos pasos, a demás bloquear registros es muy peligroso en ambiente de red y mas cuando no puedes controlar fácilmente y el registro se quede bloqueado por alguna razón.

Te explico una forma mas sencilla que uso, a ver que te parece, de esta forma no tengo necesidad de bloquear, ni necesidad de enviar un Select previo para saber el estado del registro.

Uso una tabla llamada Concurrencia, con la siguiente estructura
id    idUsuario    tabla              idRegistro   fecha
1     20               CLIENTES    50               20/07/2015 11:22:41

Importante: un Indice UNIQUE por los campo TABLA - IdRegistro

Simplemente cuando el usuario presiona el botón EDITAR del formulario, inicio una transacción del tipo 3 (foxydb), envió un .Sql(insert into..) si me marca error porque se intento duplicar el indice UNIQUE, quiere decir que otro usuario ya esta editando el registro y  por lo tanto envió un .Sql(Select ..) para saber que usuario esta editando el registro y en que fecha y hora lo tiene editando, finalizo la transacción, y muestro quien tiene editando el registro, si el insert no marca error entonces quiere decir que el registro esta libre y permito editar, y todo esto sin necesidad de bloquear registros ni consultar previamente y ni comparar fechas, es mas si no quieres decir que usuario lo tiene bloqueado el Select no seria necesario, pero si te lo recomiendo por lo que te comento mas abajo.

Supongamos que un usuario edito un registro, pero por alguna razón no puede presionar el botón de Guardar o Deshacer que son los que van a permitir eliminar el registro de la tabla Concurrencia para liberarlo y por lo tanto el registro sigue estando en la tabla Concurrencia, y no deja a los demás editarlo, muy sencillo, 2 soluciones. la primera que el mamo usuario que bloqueo el registro abra nuevamente el formulario y lo edite, por lo que el sistema según lo comentado arriba va a detectar que ya existe el registro pero cuando envió el .Sql(Select....) para saber quien es el usuario que lo tiene editando si es el mismo entonces le permito que lo edite para que al guardar o deshacer se elimine el registro.

Y para evitar mas problemas tengo una opción adicional donde muestro los registros que se están editando por tabla y usuario y desde ahí se puede eliminar el registro de la tabla Concurrencia, por si un usuario se fue a comer y urge modificar un registro que el este modificando y como su equipo puede tener contraseña no se podría 

saludos
Antonio Meza

Francisco

unread,
Jul 21, 2015, 5:41:56 AM7/21/15
to publice...@googlegroups.com, solv...@gmail.com, dire...@informatica-apliges.com, progra...@gmail.com
Antonio ese sistema tiene 2 pequeños inconvenientes:

1º) Si la modificación del registro ha sido directa desde un gestor tipo HeidiSQL no se entera y con el campo automático del tipo (CAMPO_XXX TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) si.

2º) Si un usuario se cae del sistema por apagón o como los casos que has expuesto es un fastidio tener que decirle al usuario que gestione el mismo el problema borrando la entrada en el registro de la tabla concurrencia. Aún así puedes preguntar cuando otro intenta editar si realmente quiere forzar el editado del registro, cogiendo su pertenencia.

No veo la complicación al TimeStamp quizá pq no lo tenga correctamente implementado. Te comento tan solo el código que tengo (aparte de ser muy parecida a la solución que indican para .NET en el link anterior que puse:

1º Al pulsar modificar guardo el contenido actual del campo control timestamp... algo parecido a esto:

THISFORM.VERIFICADOR=<tabla>.campo_timestamp

2º) Al guardar antes de nada me aseguro que el valor sea el mismo sino es que alguien ya ha modificado con lo que deshago los cambios (el usuario pierde todo lo que ha hecho, algo que se puede gestionar de muchas maneras pero a mi me gusta así y vuelvo a cargar el registro con los datos refrescados)

SQL="SELECT campo_timestamp FROM <tabla> ID = <id_actual_modificado>"
thisform.ClaseDatos.SQL(cSQL,"TEMP_VERIF")
IF thisform.ClaseDatos.sql_Records>0
* VERIFICAR QUE PUEDO GUARDAR
IF THISFORM.VERIFICADOR <> TEMP_VERIF.campo_timestamp
thisform.ClaseDatos.CursorClose("TEMP_VERIF")
=MESSAGEBOX("El Registro ha sido actualizado por otro Usuario. Se van a Deshacer los cambios y Refrecar la ventana "+;
"actual, para verificar los datos actualizados.",0,"NO SE GUARDARÁ LA INFORMACIÓN - CONCURRENCIA")
thisform.clasedatos.Disconnect()    
thisform.procesoeliminar(.t.) && llamo al deshacer
* REFRESCAR TABLAS
THISFORM.Refrescar_Tablas() && Refresco los cursores con los datos nuevos
RETURN .F.
ENDIF
ENDIF
thisform.ClaseDatos.CursorClose("TEMP_VERIF")

......... A partir de aquí ya guarda....
IF thisform.clasedatos.Changes() && SI HAY ALGUN CAMBIO
lHAYERROR=.F.
    IF thisform.clasedatos.Update(<tabla>)
.... etc....


Seguramente se me escapa algo. Aparte de que este método no es mi preferido dado que no advierte al usuario hasta el final y ahí lo pierdes todo. De ahí que vea mucho más lógico el caso expuesto por ti aunque esas 2 cosas que te he indicado me dejan pensativo... De todas formas muchas gracias por vuestras ayudas. 

pd: Antonio has probado a implementar por tiggers el tema de altas, bajas y modificaciones en la tabla concurrencia... Es buena opción?

Francisco

unread,
Jul 21, 2015, 8:01:12 AM7/21/15
to publice...@googlegroups.com, solv...@gmail.com, dire...@informatica-apliges.com, progra...@gmail.com
Antonio he añadido un método que devuelve .t. si se puede modificar y .f. si ya está siendo modificado. Me ha quedado más o menos así. Se supone ya estoy conectado al servidor de BBDD

LOCAL cSQL,cIDMADRE,cFECHA_HORA

Thisform.ClaseDatos.Begin(3)

cIDMADRE=THISFORM.TABLAMADRE+".ID"
Thisform.id_madre = 0
Thisform.id_madre = &cIDMADRE
cFECHA_HORA=4Transform(TTOC(DATETIME(),1), "@R 9999-99-99 99:99:99")

cSQL ="INSERT INTO CONCURRENCIA (ID_USUARIO,TERMINALRED,TABLA,ID_REGISTRO,FECHA) "+;
"VALUES ("+ALLTRIM(STR(OAPP.USUARIOACTUAL_ID,20))+",'"+OAPP.TERMINALRED+"','"+THISFORM.TABLAMADRE+"',"+ALLTRIM(STR(thisform.id_madre,20))+",'"+cFECHA_HORA+"')"

IF !Thisform.ClaseDatos.SQL(cSQL)
Thisform.ClaseDatos.RollBack()
if Thisform.ClaseDatos.Error_Odbc=1062
=MESSAGEBOX("El Registro está siendo Modificado por otro usuario. Intentelo más tarde.",0+48,"ATENCIÓN")
ELSE
=MESSAGEBOX("Error al insertar registro en tabla Concurrencia, Intentelo más tarde...")
ENDIF
RETURN .F.
ELSE
Thisform.ClaseDatos.Save()
RETURN .T.
ENDIF

Es un primer intento para ver si voy encaminado. He añadido un campo más que es TerminalRed que guardo el usuario y el nombre del equipo por si da la casualidad que el mismo usuario tiene sesiones iniciadas en otros equipos q tampoco le deje modificar. Alguna sujerencia...?



El lunes, 20 de julio de 2015, 20:11:25 (UTC+2), Antonio Meza escribió:

Antonio Meza

unread,
Jul 21, 2015, 12:14:38 PM7/21/15
to publice...@googlegroups.com, dire...@informatica-apliges.com, dire...@informatica-apliges.com, solv...@gmail.com
Hola Francisco!!

1.- No deberías manipular la base de datos desde un programa externo, ya que este rompe toda la lógica de negocios del sistema, por lo tanto no debe ser un problema, mas bien no debes permitir a un usuario manipular los datos desde HeidiSql u otro parecido, pierde garantía en automático la información.

2.- Se puede automatizar de muchas formas, incluso que al ingresar el usuario al sistema le notifique que tiene un registro editando y si lo quiere seguir editando o eliminar algo como hace Word que te recupera un archivo cuando se bloquea el equipo, formas hay muchas, por esa razón deje de usar los campos timestamp porque forzosamente tienes que bloquear el registro antes de leer el valor del timestamp para asegurarte que 2 o mas usuarios no lo vayan a leer al mismo tiempo y a todos les diga que es el mismo valor y entonces todos actualicen y se quedan los cambios del que actualizo al ultimo, y pues no te serviría de nada usarlo.

El problema de bloquear el registro es que es mas complicado de quitar el bloqueo si algo sale mal y se quedo bloqueado, a diferencia del ejemplo que puse sin necesidad de bloquear.

En tu ejemplo no estas bloqueando para obtener el valor del timestap actual del registro por lo tanto no te garantiza que si 2 o mas usuarios leen el valor al mismo tiempo van a obtener verdadero y todos podrán realizar la actualización.

Y a demás el problema que captura todos los cambios y al final le sales con que otro usuario modifico el registro primero que el y no se puede guardar te van a colgar de donde mas te duele jajajaj

En cuanto a los tiggers o store procedure no los uso, porque eso te obliga a casarte con el servidor de base de datos, creas dependencia en el, a demás si quiere cambiar de servidor de datos pues tendrías que generar lo mismo en el otro y la sintaxis no son las mismas, es mas trabajo, si lees un poco en Internet veras que los framework web en su mayoría (casi todos) ninguno hace uso de esas herramientas del servidor.

De que son buenas herramientas los son, pero prefiero no depender de ellas.

saludos
Antonio Meza

Antonio Meza

unread,
Jul 21, 2015, 12:25:59 PM7/21/15
to publice...@googlegroups.com, dire...@informatica-apliges.com, dire...@informatica-apliges.com, solv...@gmail.com
Hola !!

Es parecido al código que uso, solo que en mi caso antes del rollback envió un .Sql(Select para leer el registro y poder decirle al usuario quien es el que esta editando, para mostrárselo en el mismo mensaje, de esta forma sirve para que puedan tener comunicación entre los usuarios y hasta desbloquear si hubo algún problema.

Nota: Pero ya te decidiste a probar la opción que te comente o seguirás con los timestamp ?

saludos
Antonio Meza

Francisco

unread,
Jul 21, 2015, 1:05:21 PM7/21/15
to publice...@googlegroups.com, solv...@gmail.com, dire...@informatica-apliges.com
No Antonio, he probado los timestamp y he llegado a la conclusión de que quería un sistema que funcionara a priori de hacer las modificaciones, como dices eso de perder todo no es viable aparte de otros temas más. Así que he implementado la tabla concurrencias tal como has expuesto. Estoy en ello y de momento va todo correctamente, he añadido ya la consulta y decirle quien lo está manipulando así como el control de dicha tabla.

Antonio Meza

unread,
Jul 21, 2015, 1:21:42 PM7/21/15
to publice...@googlegroups.com, dire...@informatica-apliges.com, solv...@gmail.com
Perfecto!!! la verdad que simplifica mucho el código y te permite tener mas control y menos envíos al servidor.

saludos
Antonio Meza

Francisco

unread,
Jul 21, 2015, 1:44:48 PM7/21/15
to publice...@googlegroups.com, solv...@gmail.com, dire...@informatica-apliges.com
Una cuestión los campos id los estoy poniendo a INT de 20. Es correcta esa dimensión de la variable para contener los id´s de las tablas.

Antonio Meza

unread,
Jul 21, 2015, 2:33:26 PM7/21/15
to publice...@googlegroups.com, dire...@informatica-apliges.com, solv...@gmail.com
Depende mucho la cantidad de registros que puedas llegar a tener, hasta ahorita eh usado INT 11, anteriormente usaba Small o thynity, en tablas que se que no tendrían muchos registros, pero me encontré un articulo en Internet que se perdía mas tiempo al programar porque tenias que recordar el tamaño del campo en algo que la verdad a estos tiempos no afecta en nada.

Por ahora todos mis campos autoincrementables son INT 11, pero si crees que una tabla pueda llegar a sobrepasar ese limite puedes usar BIGINT 20 o en su caso usar siempre ese valor.

saludos
Antonio Meza

Francisco

unread,
Jul 22, 2015, 5:38:20 AM7/22/15
to Comunidad de Visual Foxpro en Español, solv...@gmail.com, solv...@gmail.com
Ok, a colación a todo esto de las modificaciones, he puesto un botón de refrescar en los formularios para volver a cargar los datos desde el servidor. Ahora estoy planteándome poner una opción que si en modo visualización (ni añadiendo ni editando) pasan x segundos (que se establezcan en el entorno) que automáticamente el form fuerce el refresh de datos. ¿Crees que es buena opción?, sería algo similar al SET REFRESH del fox. ¿Como lo ves?... 

Antonio Meza

unread,
Jul 22, 2015, 12:17:55 PM7/22/15
to Comunidad de Visual Foxpro en Español, dire...@informatica-apliges.com
Hola Francisco!!

Depende mucho del escenario, es decir para un catalogo no le veo necesidad de refrescar automáticamente ni para una factura o algo similar, para un reporte o proceso posiblemente seria lo mas adecuado, creo que con el botón que le pongas es suficiente algo como lo hace el Internet que si quieres refrescas la pantalla con F5.

En mi caso tengo una base de datos en Internet y me sirve para medir el tiempo en que realiza el mismo proceso que hago en local, por ejemplo abrir un catalogo, porque si un cliente decide montar la base de datos en Internet y los formularios están cargados o realizan muchas consultas al servidor ahí es donde tendrás problemas futuros que tardara mas en abrir o mostrar las cosas.

saludos
Antonio Meza

Jose Mario

unread,
Jul 22, 2015, 12:26:06 PM7/22/15
to Comunidad de Visual Foxpro en Español, carlosmig...@gmail.com
que bueno esta
primeros pasos maria db

Jose Mario

unread,
Jul 22, 2015, 12:36:46 PM7/22/15
to Comunidad de Visual Foxpro en Español, solv...@gmail.com, dire...@informatica-apliges.com, progra...@gmail.com
que es idregistro
es un numero unico de registro al igual que el recno()

por fa

Francisco

unread,
Jul 22, 2015, 1:07:29 PM7/22/15
to Comunidad de Visual Foxpro en Español, solv...@gmail.com
De momento para ver su funcionamiento estoy probando la BBDD con una wifi y un portatil bastante malo para detectar esos problemas... El portátil ejerce de puesto de trabajo y ataco la BBDD en mi servidor w7 de mariaDB.

Antonio Meza

unread,
Jul 22, 2015, 1:14:49 PM7/22/15
to Comunidad de Visual Foxpro en Español, maov...@gmail.com, dire...@informatica-apliges.com, progra...@gmail.com
Hola Jose Mario

En los servidores de base de datos existen al igual que en tablas de VFP ligadas a un contenedor DBC puedes usar campos autonumericos incrementables, los pones como llave primaria (primary key) que sirven para identificar un registro de otro, los famosos campos ID, entonces en cualquier tabla debes tener siempre un campo ID (de preferencia) que va a identificar al registro, por ello el nombre de IdRegistro.

El recno() es la tablas de VFP te sirve para saber la posición del puntero de registro, pero este puede variar por el indice de la tabla por lo cual nunca sera el mismo numero para el mismo registro.

En cambio el ID (puede ser cualquier nombre) un campo autonumerico incrementable que sirve para identificar un registro de una tabla, siempre va a estar ligado al registro nunca va a cambiar (salvo lo cambies manual) 

Para el ejemplo de la tabla Concurrencia, necesitas saber el nombre de la tabla y el ID del registro, por lo tanto no existe forma de que te refieras a otro registro, siempre tendrás la certeza de que sera el mismo.

La mayoría que viene de VFP y se pasa a Mysql u otro servidor de base de datos, no aprovechan todo el poder de los campos autoincrementables como llave primaria (por desconocimiento), y usan campos combinados, usan el numero de la factura, un código de cliente, etc. y ahí ya pierdes beneficios y sobre todo rendimiento.

saludos
Antonio Meza

Mario Oviedo

unread,
Jul 22, 2015, 3:01:50 PM7/22/15
to publice...@googlegroups.com
pero este puede variar por el indice de la tabla por lo cual nunca sera el mismo numero para el mismo registro.

puede variar el numero registro en una tabla recno()

no lo creo

Antonio Meza

unread,
Jul 22, 2015, 3:07:11 PM7/22/15
to Comunidad de Visual Foxpro en Español, maov...@gmail.com
Pues no lo creas, has la prueba consultando la tabla sin indices y checa el valor de recno de un registro y luego consulta la tabla con un indice y checa el valor del mismo registro con recno y ya me dices el resultado jeje

Lee bien la ayuda sobre Recno() para que veas para que sirve y despejes tu duda.

saludos
Antonio Meza

Ricardo Pina

unread,
Jul 22, 2015, 3:09:15 PM7/22/15
to Grupo VFP
Hola

El recno() puede variar si realizas un pack de la tabla y tenìa registros borrados logicamente (delete)

Saludos






--
            

                   Ricardo Pina

Desarrollo y Servicios Informáticos

                  Profesionales
               www.dsip.com.ar

 

 

Mario Oviedo

unread,
Jul 22, 2015, 3:22:44 PM7/22/15
to publice...@googlegroups.com
si tenes 5 registros y eliminas con pack
el numero 4
del 1 al 3 siguen igual
el 5 paso hacer 4

por ejmplo si eliminas el recno numero 1

el registro 2 pasa hacer 1

asi si cambia mientras no

Antonio Meza

unread,
Jul 22, 2015, 3:27:00 PM7/22/15
to Comunidad de Visual Foxpro en Español, maov...@gmail.com
Como te comente en un principio el problema es que el Recno() varia dependiendo del indice y bueno de la eliminación de registros también, por lo tanto NUNCA debe usarse para identificar un registro.

saludos
Antonio Meza

Ricardo Pina

unread,
Jul 22, 2015, 3:31:32 PM7/22/15
to Grupo VFP
Hola Antonio

El recno no varía dependiendo del indexado, varia la ubicacion en el que se muestra según criterio de indice pero su recno lo mantiene.

Saludos

Mario Oviedo

unread,
Jul 22, 2015, 3:41:09 PM7/22/15
to publice...@googlegroups.com
bueno esa es la idea, utilizar autoincremental
Reply all
Reply to author
Forward
0 new messages