Ir al contenido


Foto

Control de modificaciones e inserciones en aplicacion multiusuarios


  • Por favor identifícate para responder
13 respuestas en este tema

#1 luk2009

luk2009

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.040 mensajes
  • LocationSanto Domingo

Escrito 19 abril 2010 - 09:37

Hola como estan?

Bueno ha llegado la hora de poner mi aplicacion a funcionar en red, tengo una tabla que guarda los usuarios y los password para permitir el acceso al programa. Lo que deseo es controlar cuando alguien esta trabajando en un registro que otro usuario no pueda cambiar datos en el mismo registro y ademas que le salga un mensaje de registro en uso.

Como se debe manejar todo esto de las aplicaciones multiusuarios y cuales son los metodos correctos para hacerlo.

Gracias por adelantado.


  • 0

#2 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 20 abril 2010 - 04:50

Hola Luk.

La verdad es que hay varias formas de enfocarlo (y ninguna me gusta, pero si es imprescindible en tu aplicación, entonces tendrás que usar alguna).

Quizás la forma más sencilla sea utilizar bloqueos en la base de datos (cláusula WITH LOCK), para impedir que se modifique un registro que ya ha abierto otro usuario.

http://www.firebirds...s-withlock.html

Otra opción sería manejarlo desde tu programa Delphi. ¿ Utilizas herencia visual ?, ¿ tienes un formulario base del que heredan todos los formularios ?. Entonces programa un seguimiento de bloqueos en ese formulario base. Cada vez que se inserte/modifique un registro, dalo de alta en una tabla de bloqueos, y cuando cierres el formulario ya puedes eliminar el registro de la tabla de bloqueos.

¿ Cual es el problema de estos bloqueos ?, que pueden impedir trabajar a los demás usuarios. Imagina que alguien abre una ficha de cliente y se va a almorzar, pues ahí tienes cuatro horas en que nadie podrá actualizar ese cliente.

O bien imagina que a alguien se le apaga el ordenador y se va, dejando bloqueados todos los registros que tenía abiertos.

Otra forma de enfocar esto, es simplemente no hacer ningún bloqueo, pero detectar y avisar cuando alguien intenta modificar un registro que ya ha sido actualizado por otra persona. Esto es muy sencillo hacerlo con ClientDatasets, puesto que si utilizas el UpdateMode upWhereChanged, entonces si intentas modificar un registro en campos que han sido cambiados por otro usuario, te saltará un error y el usuario debe decidir que hacer (se suele aconsejar que se muestre una pantalla de reconciliación, mostrando el valor de los campos que intentas modificar, y el de los cambios que ha echo el otro usuario).

Saludos.

  • 0

#3 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 20 abril 2010 - 06:11

Saludos.

Pienso igual que Marc, pero todo depende realmente de lo que se necesite.

En el asunto de los bloqueos utilizo FibPlus y por ende es simplemente hacer una llamada a un método pero corro el riesgo ya mencionado por Marc que se quedaría bloqueado el registro de manera indefinida; es totalmente valido y recomendable cambiar el valor del UpdateMode a upWhereChanged ademas de que esto hace más "light" tus sentencias de actualización.

Si es posible, podrías explicarnos el escenario que tienes a mano para ver que solución más viable le podemos encontrar.
  • 0

#4 luk2009

luk2009

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.040 mensajes
  • LocationSanto Domingo

Escrito 20 abril 2010 - 06:20

Gracias Marc por tu respuesta, que como siempre es muy acertada y bien completa.

Voy a revisar todo lo que me has dicho, pero me gustaria saber, si solo es por el asunto de la operatividad  del software que no te gustan las opciones o si hay otras razones.

Rolphy aqui estoy Poniendo un poco en contexto la situacion:

-El software esta abierto en varios computadores conectados en red local o por internet.
-Cuando una alarma de un cliente llega, se abre automaticamente un formulario donde el operador tiene que escribir las notas de las operaciones que realiza y donde estan las informaciones generales del cliente, asi como los numeros de telefono a los cuales llamar:Imagen Enviada


-lo que quiero evitar es que este formulario se abra con este mismo registro, en alguna de las otras computadoras donde el software este abierto. Ademas me gustaria que le indicara al otro computador

PD. Esta es una version hecha en lazarus, aunque la original esta hecha en delphi.
      Uso Zeos y firebird 2.1
  • 0

#5 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 20 abril 2010 - 07:06

Hola Luk.

No me gusta porqué es fácil que queden bloqueos permanentes (gente que se va con la pantalla abierta, ordenadores colgados, etc. ...), y los usuarios que no puedan entrar en las fichas que necesitan van a culpar (con razón) al programa. Además cargas más trabajo al Servidor (o bien lanzas más consultas para establecer los bloqueos, o bien mantienes los bloqueos sobre los mismos registros de la base de datos, lo cual también es costoso para el motor).

La solución que menos carga conlleva, y que por tanto afecta menos al rendimiento del programa, es la de detectar si hay conflictos a posteriori, en el momento de intentar guardar los datos (con el UpdateMode a upWhereChanged, como comentábamos con Rolphy).

Pero para un caso tan sencillo como el que planteas, yo no me complicaría la vida e iría a la solución "clásica". Es decir, añadir la tabla de bloqueos, y cada vez que abres un registro, lo añades a la tabla de bloqueos, eliminando el bloqueo al cerrar la ficha (evidentemente antes de añadir tu bloqueo, tienes que comprobar que no haya otro usuario que lo haya bloqueado antes).

En la tabla de bloqueos solo tienes que guardar el ID de la Tabla a bloquear y el ID del Registro bloqueado. Aunque es bastante útil guardar también hora del bloqueo así como el ID del usuario que lo ha realizado y el nombre o la IP de la máquina desde el que lo ha hecho. De esta forma cuando te encuentras con un bloqueo, puedes indicarle al usuario que otra persona está manteniendo ese bloqueo, y además te permite eliminar los bloqueos de una determinada máquina, si esa máquina se ha colgado sin haber podido eliminar ella misma los bloqueos que tenía.

Si quieres avisar a otro computador de que quieres entrar en su registro bloqueado, en la tabla de bloqueos tienes el nombre del computador que mantiene el bloqueo, así que o bien haces tu propio mecanismo para poder notificar el aviso a ese computador (mediante las Indy, por ejplo.) o bien puedes hacer que el Servidor Firebird lance un Evento que sea capturado por el computador al que va destinado.

NOTA: Estas opciones necesitan que puedan llegar conexiones entrantes, por lo que los Firewalls de los ordenadores pueden hacer que no funcionen bien. Así que otra opción es que cuando quieras mostrar un aviso para un ordenador, puedes anotarlo en un campo para ello en la tabla de bloqueos, para el registro bloqueado. De forma que el ordenador que mantiene una ficha abierta y por tanto el registro bloqueado, cada x segundos puede consultar la tabla de bloqueos para ver si alguien ha anotado que se muestre un aviso para ese registro.

Saludos.
  • 0

#6 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 20 abril 2010 - 07:59

No está demás aclarar que emplear el uso de bloqueos explícitos como el WITH LOCK que ofrece Firebird debe ser tomado con pinzas y analizarse adecuamente si es realmente necesario.
Por lo general los motores de base de datos poseen los medios para garantizar de que las operaciones y cambios entre los campos pueda mantenerse consistentes sin requerir de un bloqueo explícito.

Ahora bien por lo que entiendo de tu explicación, la posibilidad de contar con la tabla de bloqueos que comenta Marc me parece acertada. Incluso combinandolo con el poder de los triggers, SP y eventos se puede conseguir que cuando un registro entre a la tabla de bloqueos y alguien intente obtener estos registros se disparen eventos. El sistema cliente los captura y podría informar de ello.
Por ejemplo: cuando un registro se bloquea se puede concebir que el aplicativo registre un evento del tipo "Avisame que he alguien quiere usar un registro bloqueado" y/o del mismo modo, para quien pide el registro que se le informe de que alguien más lo tiene bloqueado.
Esto podría evitar el tener que recurrir a otras opciones, como las Indy que comenta Marc. Creo que esta es la mejor opción: eventos.

Saludos,
  • 0

#7 pcicom

pcicom

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 267 mensajes
  • LocationMéxico

Escrito 20 abril 2010 - 08:27

Te convendria crear una TABLA de EVENTOS atendidos o ALERTADOS, donde cuando a alguna PC que se le MUESTRE el AVISO, su primer accion sera grabar el NOMBRE de la MAQUINA y un estatus de ALERTADO.

Las OTRAS maquinas o TODAS tendrian que checar este ESTATUS para revisarlo si ya fue tomado por OTRA maquina o no..
de esa manera se mostrara o no, segun el estatus..

El estatus ya despues lo podras modificar segun tus necesidaes..

SALUDOS..


  • 0

#8 eduarcol

eduarcol

    Advanced Member

  • Administrador
  • 4.483 mensajes
  • LocationVenezuela

Escrito 20 abril 2010 - 08:28

A ver, entiendo que lo que no quieres es que al mostrarse la alarma en una estación se muestre en la otra. A mi se me ocurre es un campo de estado donde indicas si el registro ya fue visualizado, y este se actualiza cuando el registro se muestre en la pantalla.

jeje se me adelanto pcicom, la idea es la misma
  • 0

#9 luk2009

luk2009

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.040 mensajes
  • LocationSanto Domingo

Escrito 20 abril 2010 - 08:31

Gracias Marc por tu respuesta. Me gusta la idea de la tabla bloqueos, porque esto me permite llevar tambien un registro de la forma en que los operadores manejaron el registro. La idea seria que cuando se abra el formulario notas, automaticamente se inserte bloqueo_numero,  el numero del registro bloqueado, el numero del cliente, la identificacion del operador, IP de la maquina (que no se como buscarlo y no quisiera usar las indy), fecha del bloqueo y un campo estatus del bloqueo.

Este ultimo campo me tiene confuso, porque la verdad Marc que no entendi bien como hacer esto:

eliminando el bloqueo al cerrar la ficha


Si con esto te refieres a cambiar el estatus del bloqueo, pues perfecto, porque en el onclose del formulario notas, puedo hacer que cambie el estatus de ese campo.

Pcicom gracias por tu respuesta, La verdad es que es practicamente lo mismo que me indica Marc, pero adicionando lo del estatus, que me parece correcto. Me gusta la idea de Marc de crear una tabla con mas datos, porque esto me permite tener mayor informacion del manejo de los registros por parte de los operadores.

gracias Eduarcol por tu respuesta y te indico lo mismo que a Pcicom, me gustaria tener mayor informacion y si creo un campo estatus solamente, esto no me permitiria saber quien tiene el registro abierto y desde donde.

El problema que tengo es que por ejemplo pueden llegar varias alarmas de un mismo cliente y cada una de estas alarmas crea un registro independiente, por lo tanto necesito bloquear todas las alarmas de este cliente, para que otro operador no este llamando al mismo cliente desde otro lado.

ejemplo

Cliente#  fecha                              evento      detalle
0001      20/04/10 11:00:20 pm        BA01        Robo zona 1 Puerta de entrada
0001      20/04/10 11:00:25 pm        BA02        Robo zona 2 Detector infrarojo


Esto puede pasar y no quiero que un operador llame por la alarma en la zona 1 y otro por la alarma en la zona 2.

Todo esto me plantea un problema adicional, Necesito crear una especie de secuencia en la apertura de los formularios ya que cuando llega una alarma, el formulario notas se abre automaticamente y logicamente se va a abrir en todos los computadores que tengan el software abierto, lo cual no es necesario. Creen que debo crear otro hilo con este inconveniente o piensan que es parte del asunto primario.?


  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 20 abril 2010 - 09:10

Hola Luk2009,
Ahora tengo los cables chamuscados y no me da la cabeza para pensarlo detenidamente.
Necesitaría darme un tiempo para digerir las ideas.

Así de forma apresurada creo que podría diseñarse la tabla para que sólo registre el primer aviso detectado. Una consulta sobre la tabla para ver si ya hay un evento para el cliente en cuestión debería bastar para saber si hay que registrar más avisos de eventos o no.
Al menos eso es lo voy entendiendo.
Yo entiendo que lo que buscas es que sólo avise una vez por más que se reciban más alertas ¿es así?

Respecto a lo que remarcas con rojo... allí ya me hice bolas... :( :| ¡me hace falta dormir un poco!
Considero que todo podría tratarse en este hilo, en todo caso quizá sea aconsejable editar el título para aclarar que aquí se está tratando de una especie de caso particular de control de recurrencia en entorno multiusuarios (o sería mejor... C/S)

Saludos,

  • 0

#11 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 21 abril 2010 - 07:02

Hola Luk

Este ultimo campo me tiene confuso, porque la verdad Marc que no entendi bien como hacer esto:

eliminando el bloqueo al cerrar la ficha


Si con esto te refieres a cambiar el estatus del bloqueo, pues perfecto, porque en el onclose del formulario notas, puedo hacer que cambie el estatus de ese campo.


En realidad me refería a simplemente eliminar de la tabla de bloqueos el registro que nos indica de que ese cliente está bloqueado. Y en efecto, el OnClose del formulario podría ser un lugar perfecto para ello.

Es decir, no creo que los bloqueos debas hacerlos cambiando el estado de un campo, sino que me parece mejor hacerlos añadiendo y eliminando registros en una tabla de bloqueos.

Si fueras a utilizar un campo de estado, entonces no necesitas para nada la tabla de bloqueos, podrías mantener ese estado directamente en la tabla de clientes. Pero como siempre resulta interesante mantener la hora, el usuario, el ordenador, ... que han activado el bloqueo, por eso me parece mejor mantenerlo en una tabla separada de bloqueos.

Respecto a la otra consulta, la verdad es que no lo he acabado de entender, creo que si lo puedes volver a expresar en otro hilo, quizás sea mejor.

Saludos.

  • 0

#12 luk2009

luk2009

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.040 mensajes
  • LocationSanto Domingo

Escrito 21 abril 2010 - 10:29

Marc entiendo mejor tu punto. La verdad es que me gustaria tener un historial de los movimientos de los operadores entorno a las alarmas que llegan y pensaba que podria utilizar la tabla bloqueos para ello, pero creo que eso haria menos practico el funcionamiento de dicha tabla. La idea de borrar e insertar hace mas simple y rapida la busqueda de bloqueos.

Sobre el otro problema tratare de explicarme mejor. Vamos a poner el siguiente escenario:
-hay 3 computadores con el software abierto recibiendo las alarmas que llegan

-llega la alarma:
registro#    cliente#    nombre  fecha                                  evento      detalle
10010        0001        luk2009  21/04/2010 10:10:20pm          ba01        robo zona 1 puerta de entrada

-El formulario se va a abrir al mismo tiempo en todos los software que esten corriendo y por lo tanto realizaria las mismas operaciones en cada uno de ellos. Es decir por ejemplo cada aplicacion en todos los computadores donde este corriendo intentarian bloquear el registro.

Eso puede provocar que el programa se pare u otra cosa, ademas que no tiene sentido que haga eso.

Lo que deseo hacer es una secuencia de apertura de formularios, para lo cual tengo que saber cuantas computadoras tienen el software abierto monitoreando las alarmas y crearle una especie de fila u orden.

La idea que me llega es que cuando corra una aplicacion esta al iniciar busque cuantas mas estan abiertas y sin por ejemplo hay 3, que ella ponga una variable u otra cosa  en 4. cuando llegue una alarma debo tener algun contador que me indique cual fue la ultima aplicacion que abrio un formulario y entonces solo abrir el formulario en la aplicacion siguiente en el orden.

Ejemplo si la alarma se abre en la aplicacion del computador 5, cuando llegue la proxima alarma se abrira en el computador 6 o en el 1 si no hubiera mas de 5. Esta es una idea que me llega, pero siento que podria ser complicado ponerla en practica.

Reitero las alarmas llegan y abren un formulario automaticamente y si solo hay una aplicacion corriendo pues no hay problema, el problema esta cuando hayan 4 computadores con la misma aplicacion, porque el formulario estaria abriendose en las 4 al mismo tiempo y enviando 4 bloqueos a ese registro al mismo tiempo.


Como puedo resolver este problema?





  • 0

#13 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 22 abril 2010 - 10:38

Marc entiendo mejor tu punto. La verdad es que me gustaria tener un historial de los movimientos de los operadores entorno a las alarmas que llegan y pensaba que podria utilizar la tabla bloqueos para ello, pero creo que eso haria menos practico el funcionamiento de dicha tabla. La idea de borrar e insertar hace mas simple y rapida la busqueda de bloqueos.


Sí, es mejor que el tema de un historial de movimientos lo pongas en otra tabla y mantengas los bloqueos lo más sencillo posible.

Sobre el otro problema tratare de explicarme mejor. Vamos a poner el siguiente escenario:
-hay 3 computadores con el software abierto recibiendo las alarmas que llegan

-llega la alarma:
registro#    cliente#    nombre  fecha                                  evento      detalle
10010        0001 begin_of_the_skype_highlighting              10010 0001      end_of_the_skype_highlighting        luk2009  21/04/2010 10:10:20pm          ba01        robo zona 1 puerta de entrada

-El formulario se va a abrir al mismo tiempo en todos los software que esten corriendo y por lo tanto realizaria las mismas operaciones en cada uno de ellos. Es decir por ejemplo cada aplicacion en todos los computadores donde este corriendo intentarian bloquear el registro.

Eso puede provocar que el programa se pare u otra cosa, ademas que no tiene sentido que haga eso.

Lo que deseo hacer es una secuencia de apertura de formularios, para lo cual tengo que saber cuantas computadoras tienen el software abierto monitoreando las alarmas y crearle una especie de fila u orden.

La idea que me llega es que cuando corra una aplicacion esta al iniciar busque cuantas mas estan abiertas y sin por ejemplo hay 3, que ella ponga una variable u otra cosa  en 4. cuando llegue una alarma debo tener algun contador que me indique cual fue la ultima aplicacion que abrio un formulario y entonces solo abrir el formulario en la aplicacion siguiente en el orden.

Ejemplo si la alarma se abre en la aplicacion del computador 5, cuando llegue la proxima alarma se abrira en el computador 6 o en el 1 si no hubiera mas de 5. Esta es una idea que me llega, pero siento que podria ser complicado ponerla en practica.

Reitero las alarmas llegan y abren un formulario automaticamente y si solo hay una aplicacion corriendo pues no hay problema, el problema esta cuando hayan 4 computadores con la misma aplicacion, porque el formulario estaria abriendose en las 4 al mismo tiempo y enviando 4 bloqueos a ese registro al mismo tiempo.


Como puedo resolver este problema?


A mi también me parece complicado de llevar a la práctica. Sobretodo porqué no es nada fácil saber cuantas computadoras clientes están en activo (¿ cuando te darás cuenta de que una computadora se ha colgado ?, ¿ de que se ha desconectado ?, etc. ...). Creo que sería fácil encontrarte con alarmas que nadie atiende, porqué la has asignado a un ordenador que por vete a saber que razón en ese momento deja de estar activo.

Creo que lo puedes hacer bastante más sencillo. Dices que si hay cuatro computadoras activas, las cuatro recibirán la alarma y las cuatro intentarán bloquear el registro para poder mostrarlo.

La verdad es que a mi eso ya me parece bien. Solo una de esas cuatro computadoras conseguirá establecer el bloqueo, y esa es la que mostrará el formulario de la alarma, en cambio las otras tres computadoras fallarán en su intento de bloquear el registro, recibirán una excepción de que el registro ya está bloqueado, por lo que ya no deben intentar cargar su formulario y simplemente se deben quedar a la espera de que lleguen más alarmas para poder conseguir bloquear una y entonces mostrarla.

Lo único que hay que ser cuidadoso es en el momento de crear el mecanismo de bloqueo de registros. Hay que impedir que dos computadoras puedan bloquear a la vez el mismo registro si ambas inician su transacción de bloqueo al mismo instante. Solo una computadora debería poder bloquear un registro, incluso si la petición en el mismo momento. Para ello quizás tengas que usar un ISOLATION LEVEL superior al que se usa habitualmente.

Saludos.
  • 0

#14 luk2009

luk2009

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.040 mensajes
  • LocationSanto Domingo

Escrito 22 abril 2010 - 01:44

Gracias Marc por tomarte el tiempo en responder
Como siempre tienes razon. Aunque las cuatro computadoras que menciono de ejemplo traten de abrir el formulario, solo una lo va a lograr, porque ya tengo un mecanismo que impide que se abra mas de un formulario en la aplicacion al momento de llegar una alarma y como el bloqueo se establece en el onshow del formulario, si ese operador esta ya manejando una alarma, el fomulario se va a abrir en una computadora que no tenga tenga un formulario abierto y esa computadora es la que va a bloquear el registro.  Solo me queda manejar el asunto del isolation level o buscar algun mecanismo que permita para regular cual tiene prioridad sobre el bloqueo del registro.

gracias de nuevo y me pondrè a trabajar con estas ideas.


  • 0




IP.Board spam blocked by CleanTalk.