di por favor, luego gracias
unread,May 7, 2009, 3:52:50 PM5/7/09Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Mundo Visual FoxPro
Asumamos que tienes 2 tablas libres que quieres compartir. Estas
tablas se llaman CLIENTES.DBF y PRODUCTOS.DBF
Primera forma:
==========
Set Exclusive Off
Use CLIENTES in 0
Use PRODUCTOS in 0
Explicación:
Toda tabla que abras después de haber dado la instrucción "Set
Exclusive Off" se abrirá en modo compartido. Si deseas dejar de
seguir abriendo tablas en modo compartido, deberás incluir el comando
"Set Exclusive On" para que las tablas que abras luego de este comando
no sean compartidas sino "exclusivas".
Segunda forma:
==========
Use CLIENTES in 0 Shared again
Use PRODUCTOS in 0 Shared again
Explicación:
Toda tablas que al abrirla de agreges la palabra "Shared" se abrirá en
modo compartido. Si NO DESEAS que la tabla se abra en modo
compartido, deberás usar la palabra "Exclusive" en vez de la palabra
"Shared".
Adicionalmente:
===========
Por razones de la "lógica" de tu programa o razones de código de FOX,
algunas veces necesitarás "bloquear" una tabla que habías abierto en
modo "compartido". "Bloquearla" significa que solo el usuario que la
bloquéo podrá escribir en ella, hasta
que este mismo usuario la haya desbloqueado. Por ejemplo, si estas
modificando el Saldo Pendiente de un cliente, sería sabio "Bloquear la
tabla" mientras cambias el saldo para que no pueda entrar un usuario
desde otra estación y trastornar tu trabajo. Luego de que hayas echo
tu modificación, NO SE TE DEBE OLVIDAR desbloquear la tabla para que
cualquier otro usuario pueda trabajar con ella de la manera que tu lo
hiciste.
Para bloquear una tabla, debes usar la función FLOCK(tabla). Esta
función te devuelve .T. si logró bloquear la tabla y .F. si no lo
logró. Puede ser que el usuario "A" no logre bloquear la tabla porque
el usuario "B" ya la tenía bloqueada y hay que esperar a que el
usuario "B" la "libere". Por ejemplo
IF FLOCK("CLIENTES")
* Quiere decir que si se pudo bloquear "CLIENTES", entonces pones
aquí tu
* código que modifica el Saldo del Cliente.
ELSE
* Quiere decir que no se pudo bloquear "CLIENTES", entonces debes
poner un
* aviso indicándole al operador que debe esperar unos segundos en
lo que alguien
* que tiene agarrada la tabla, por fin la libera. Esto debería ir
en un LOOP.
ENDIF
Para liberar las tablas que estan blockeadas debes utilizar el comando
UNLOCK.
Finalmente 2 cositas:
1- A veces no es necesiario bloquear TODA la tabla, sino solamente un
registro de
la tabla (o ciertos registros). Para bloquear un registro
específico solamente,
debes usar la función RLOCK() en lugar de la función FLOCK()
2- Otros comandos relativos al bloqueo y desbloqueo son:
SET MULTILOCKS ON/OFF que le avisa a Fox que permita o no permita
bloquear a la vez varios registros individuales de una tabla (o
las tablas).
SET REPROCESS TO "n" que le indica a Fox cuantos segundos debe
esperar
reintentar lograr un bloqueo existos con FLOCK() o RLOCK(). Si le
pones -1,
Fox se quedará eternamente intentando blockear la tabla hasta que
lo logre.
*-------------------------------------------------------------------------------------------------------------------------------
No es que hayan funciones y/o comandos "mas aconsejables" y otros "no
tan aconsejables". Mas bien, tienen diferente propósito, pensando en
los diferentes escenarios programáticos que podrías encontrar. Mejor
me explico con un ejemplo:
Supongamos que tenemos la tabla CLIENTES. Imaginemos que tenemos una
oficina de Telemarketing donde tenemos 5 chicas llamando a
"potenciales" clientes por teléfono y que cada chica tiene una
estación (esto haría, 5 estaciones a la vez).
El trabajo de las chicas consiste en "Agregar" nuevos clientes a
nuestra tabla CLIENTES o en "Modificar (actualizar)" los datos de
clientes ya existentes en la tabla. Las 5 estaciones que estan
utilizando las chicas son "idénticas", con el mismo sistema operativo,
con el mismo software, la misma velocidad de procesador, la misma
memoria RAM, el mismo tamaño de disco duro (compraro todo igual,
cuando se "montó" este negocio de Telemarket).
CASO 1
======
Son las 3:15 PM. En este preciso momento 3 DE LAS CHICAS acaban de
terminar de capturar información de 3 NUEVOS CLIENTES y resulta que
"AL MISMO TIEMPO" las tres chicas pulsan el botón "Guardar" de tu
formulario de "Captura de Nuevos Clientes". Por favor, para este
ejemplo OLVIDATE TOTALMENTE de los campos "Autoincrementales" y quiero
que imagines que el "Código de Cliente" es un campo Númerico
Correlativo. A medida que agregas un nuevo cliente, este campo se
incrementa en +1. Actualmente nuestra tabla tiene grabados 500
clientes y el último Código Correlativo dado es el 500. Como no estas
usando campos Autoincrementales, tu tienes una pequeña subrutina que
busca el último código dado, le suma 1 y de esa manera obtienes el
siguiente "nuevo código correlativo disponible".
Problema:
----------
Si las chicas pulsan "Click" en el botón "Guardar" AL MISMO TIEMPO,
¿ Como te aseguras de que tu rutina que busca el último código
otorgado (el 500) no se ejecute por triplicado y "COMETA EL ERROR" de
decirle a las 3 chicas al mismo tiempo que el siguiente Código
Correlativo disponible es el 501y que los 3 nuevos clientes sean
guardados erróneamente con el nuevo código 501 repetido ? Si no tomas
ninguna medida al respecto, resulta altísima la probabilidad de que
los 3 nuevos clientes que se agregen, agarren el Código Correlativo
No. 501. Claro, no necesariamente va a suceder esto, pero la
posibilidad de este error es "Altísima".
Solución:
---------
Bueno, no importa que "Aparentemente" las tres chicas den "Click" al
botón "Guardar" exactamente al mismo tiempo, como tu sabes, en las
computadoras las cosas suceden en milésimas de segundo, por lo que con
toda certeza aunque humanamente no podamos notarlo, ellas habrán dado
"click" con algunas milésimas de segundo de diferencia, lo que implica
que alguna de ellas fue la "Primera" en obtener el Siguiente Código
Correlativo disponible (el 501) y las otras le siguieron
sucesivamente, pero como aún "No se ha grabado nada" en la tabla
física, las otras también obtuvieron el número 501 como el siguiente
disponible.
Por esta razón utilizarás el FLOCK("CLIENTES") para que la primera que
agarre el archivo para ver cual es el Código Correlativo que toca, de
una buena vez, bloquee el archivo para si misma y de esta manera "No
permita" que las otras puedan bloquearlo (Teóricamente a las otras
chicas les aparecerá un error de "Archivo bloqueado").
Entonces esta chica (la privilegiada que logró obtener el primer FLOCK
()), logra bloquear para sí misma el archivo, obtiene como siguiente
Código Correlativo disponible el 501, "Graba" a su nuevo cliente (con
el código que tu ya habías elaborado para este fin) y seguidamente, al
haber grabado al nuevo cliente debiera de ejecutar un UNLOCK para
liberar la tabla CLIENTES.
Mientras todo esto sucede con la "Chica 1", las otras chicas
obtuvieron un resultado
de su función FLOCK(), lo cual es un problema si tu no hiciste ningún
código que contemple esta posiblidad (a ellas les salrá un mensaje de
error). Ahora bien, para que ellas no tuvieran un mensaje de error
tendrías 2 opciones:
1- La larga y complicada: que tu IF tenga un ELSE que las mande a
mostrar un mensaje que diga "Espere mientras se graba otro cliente" y
luego meter eso dentro de un DO WHILE para que vuelva a intentarse
otro FLOCK() o
2- La solución mas simple y directa: Que antes de cualquier FLOCK
hubieras dado el comando:
SET REPROCESS TO -1
para que el FLOCK() de las 3 chicas se quede por sí mismo en un "LOOP
Eterno" esperando a que el arhcivo se desbloquee y continuar con las
siguientes líneas de código hasta que el FLOCK() devuelva un .T. (es
decir, que si logró bloquear la tabla CLIENTES.DBF).
Claro que con las velocidades que manjenan los equipos el día de hoy,
te diría que esto sucede en fraciones de segundo, pero te cuento que
tengo una Red Local con un caso similar a este ejemplo donde hay 48
estaciones agregando todo el tiempo "Nuevos Clientes" a la tabla
CLIENTES en una oficina de Telemarket y te cuento que a manera de
prueba, un día hicimos que todos pulsaran "Click" al botón "Guardar"
al mismo tiempo y fue muy notorio que la ultima estación en obtener un
FLOCK() exitoso tardó aproximadamente 15 segundos en "desbloquearse".
Se quedó congelada durante 15 segundos, como si FOX se hubiera
"colgado", pero lo que pasaba es que era la última de la cola de
peticiones de bloqueo (FLOCK()) que se formó en el servidor y se
mantuvo "trabada" intentando una y otra vez hacer el FLOCK hasta que
otras "Desbloquearan" el archivo (UNLOCK) consecutivamente en la
medida que fueron agregando cada una a su nuevo cliente a la tabla y
por fin la última máquina logró agregar al último cliente
respectivamente.
CASO 2
======
Imagina el mismismo escenario del CASO 1, pero resulta que en esta
ocasión algunas chicas estan agregando Clientes Nuevos (Caso 1
anterior) y otras chicas estan solamente Actualizando datos (Cambiando
teléfonos, dirección, preferencias comerciales, etc.).
Ahora bien, por muy "mala suerte" 2 de las chicas llaman a casa de los
Simpson y una de ellas habla con Homero Simpson y la otra con Bart
Simpson. Ambas estan pidiendo una actualización del número de
contribuyente del IRS. Como este par son unos pillos y descubrieron
que las 2 chicas estan llamando al mismo tiempo, se han puesto de
acuerdo en dar números diferentes solo por la pura gana de fastidiar a
las operadoras.
Solución:
======
Bueno, tu como buen "Analista en Sistemas" ya habías previsto que esto
pudiera pasar y para evitar que 2 chicas intenten Actualizar
"simultáneamente" un MISMO REGISTRO (cliente en nuestro ejemplo). Para
no mandar un FLOCK("Clientes") y bloquear TODA LA TABLA DE CLIENTES,
perjudicando a las chicas que estan agregando clietnes, solamente
mandas un RLOCK() para bloquear el registro específico que estas
modificando, de esta suerte cuando otra chica intente modificar el
mismo cliente, debería salirle un mensaje indicando que otra persona
"Ya está Modificando" a dicho cliente y que tiene que esperar a que la
otra chica termine (aun
si la otra chica se fuera a tardar 2 horas modificando este registro).
El punto es que tu, desde tu código, tengas la "prevención" de evitar
que un mismo cliente pueda ser Modificado (actualizado) por 2
estaciones diferentes a la misma vez, a fin de evitar conflictos de
información (no de programación ni de VFP 9).
No es asunto de que VFP 9 no pueda permitir que 2 o mas estaciones
modifiquen (actualizen) un registro a la vez, es asunto de que tanto
le conviene a tu programa aplicado. Es tu deber evitar situaciones
potencialmente "conflictivas" que pongan en peligro la integridad,
veracidad y confiabilidad de la información.
FINALMENTE
===========
Lo del Buffering, como decimos en mi tierra, es "harina de otro
costal" que si está intimamente relacionado con lo arriba expuesto,
pero que a su vez confronta el problema desde una perspectiva mucho
mas "tecnificada" y "especializada" a nivel informático. Si para
describir algo tan simple como el FLOCK el RLOCK y el UNLOCK mira el
gran "testamento" que escribí arriba, te digo que para discutir sobre
el Buffering podríamos escribir toda una Biblia ya que el Buffering
agrega muchas mas posibilidades a todo la arriba descrito,
enriqueciendo mucho mas la experiencia del manejo de tablas en un
entorno multiusuario.
Yo vengo programando desde tiempos de Foxpro para DOS versión 1 y te
cuento que hasta la fecha solo en una ocasión he necesitado meterme a
manejar el Buffering en una aplicación hecha para una empresa donde
habían 10 chicas facturando a la vez de un mismo inventario y existía
la complicación de que facturaran del mismo producto del cual habían
por ejemplo solo 10 unidades disponibles y una chica quería 7 y la
otra 8 al mismo tiempo. Lo duro era que las a una de las chicas le
podría despachar lo que pedía, pero a la otra debería decirle que solo
le podría despachar la diferencia de 10 menos lo que la otra hubiera
pedido (3 o 2, según el caso). Pero lo peor sería si por alguna
razón, la chica que ordenó 7 (por ejemplo) luego de 10 minutos de
estar tomando el resto del pedido, se arrepintiera y decidiera ya no
grabar el pedido (necesitando hacer un "TableRevert()" de lo que había
"tomado" temporalmente mientras hacía el pedido), dejando el producto
disponible para la otra chica a la que originalmente se le había
denegado por "falta de existencia".
Una verdadera PESADILLA. Te digo, solo en esa ocasión he necesitado
usar el Buffering. Y te digo, ese programa lo hice en 1,992 con Foxpro
2.0 para DOS, cuando ni soñaba con aparecer el "Buffering" y en
aquella ocasión lo solucioné utilizando campos temporales. Luego,
cuando la aplicación migró a Visual Fox 7, utilizamos entonces el
"Buffering" para resolver este rompecabezas.
Ojalá hayas tenido la paciencia y el tiempo de llegar hasta el final
de este "testamento".