versión 11 (Modificado)
4D y 4D Server administran automáticamente las bases evitando conflictos entre procesos o entre usuarios. Dos usuarios o dos procesos no pueden modificar el mismo registro u objeto al mismo tiempo. Sin embargo, el segundo usuario o proceso puede acceder simultáneamente al registro en modo sólo lectura.
Hay muchas razones para utilizar los comandos multiusuario:
Modificación de registros por programación.
Utilización de una interfaz de usuario personalizada para operaciones multiusuario.
Almacenamiento de modificaciones relacionadas con una transacción.
Hay tres conceptos importantes a tener en cuenta cuando se utilizan comandos en una base multiproceso:
Cada tabla está en modo sólo lectura o lectura/escritura.
Los registros se bloquean cuando son cargados y se desbloquean cuando son descargados.
Un registro bloqueado no puede ser modificado.
En las siguientes secciones como convención, la persona que efectúa una operación en la base multiusuarios es el usuario local. Las otras personas que utilizan la base son los otros usuarios. La discusión es desde el punto de vista del usuario local. De la misma forma, desde el punto de vista multiproceso, el proceso que se ejecuta una operación en la base es el proceso actual. Todo otro proceso en curso de ejecución está diseñado como otro proceso. La discusión es desde el punto de vista del proceso actual.
Bloqueo de registros
Un registro bloqueado no puede ser modificado por el usuario local o el proceso actual. Un registro bloqueado puede ser cargado, pero no modificado. Un registro se bloquea cuando uno de los otros usuarios o procesos ha cargado el registro para efectuar una modificación. Sólo el usuario que modifica el registro ve el registro como desbloqueado. Todos los otros usuarios y procesos ven el registro como bloqueado, y por lo tanto no disponible para modificación. Una tabla debe estar en modo lectura/escritura para que un registro se cargue como desbloqueado.
Modo sólo lectura y lectura/escritura
Cada tabla de una base está en modo lectura/escritura o en modo sólo lectura para cada usuario y proceso de la base. Sólo lectura significa que los registros de la tabla pueden ser cargados pero no modificados. Lectura/escritura significa que los registros de la tabla pueden ser cargados y modificados si ningún otro usuario/proceso ha bloqueado el registro previamente.
Note que si cambia el estado de una tabla, el cambio toma efecto para el siguiente registro cargado. Si ya hay un registro cargado cuando cambia el estado de la tabla, el registro no se afecta por el cambio de estado.
Estado sólo lectura
Cuando una tabla está en modo sólo lectura y se carga un registro, el registro está siempre bloqueado. En otras palabras, el registro puede mostrarse, imprimirse, y utilizarse, pero no modificarse.
Note que el modo sólo lectura aplica únicamente a la edición de registros existentes. El estado sólo lectura no afecta la creación de nuevos registros. Puede añadir registros a una tabla sólo lectura utilizando los comandos CREATE RECORD y ADD RECORD o los comandos de menús del entorno Diseño.
4D define automáticamente una tabla en modo sólo lectura para los comandos que no requieren acceder en escritura a los registros. Estos comandos son:
Puede saber en cualquier momento el estado de una tabla utilizando la función Read only state.
Antes de ejecutar cualquiera de estos comandos, 4D guarda el estado actual de la tabla (sólo lectura o lectura/escritura) para el proceso actual. Después de ejecutar el comando, el estado inicial se restablece.
Estado lectura/escritura
Cuando una tabla está en lectura/escritura y se carga un registro, el registro estará desbloqueado si ningún otro usuario ha bloqueado el registro primero. Si el registro está bloqueado por otro usuario, el registro se carga como un registro bloqueado que no puede ser modificado por el usuario local.
Una tabla debe estar en modo lectura/escritura y el registro cargado para que sea desbloqueada y por lo tanto modificable.
Si un usuario carga un registro de una tabla en modo lectura/escritura, ningún otro usuario puede cargar ese registro para modificación. Sin embargo, otros usuarios pueden añadir registros a la tabla, bien sea a través de los comandos CREATE RECORD o ADD RECORD o manualmente en el entorno Diseño.
El modo lectura/escritura es el estado por defecto para todas las tablas cuando una base se abre y se inicia un nuevo proceso.
Cambiar el estado de una tabla
Puede utilizar los comandos READ ONLY y READ WRITE para cambiar el estado de una tabla. Si quiere cambiar el estado de una tabla para volver un registro de sólo lectura o lectura/escritura, puede ejecutar el comando antes de cargar el registro. Todo registro ya cargado no se ve afectado por los comandos READ ONLY y READ WRITE.
Cada proceso tiene su propio estado (sólo lectura o lectura/escritura) para cada tabla en la base.
Cargar, modificar y descargar registros
Para que el usuario local pueda modificar un registro, la tabla debe estar en modo lectura/escritura y el registro debe cargarse y desbloquearse.
Cada uno de los comandos que carga un registro actual (si hay uno), tales como NEXT RECORD, QUERY, ORDER BY, RELATE ONE, etc., define el registro como bloqueado o desbloqueado. El registro se carga en función del estado actual de su tabla (sólo lectura o lectura/escritura) y de su disponibilidad. Un registro también puede cargarse de una tabla relacionada por uno de los comandos que provoca una relación automática.
Si una tabla está en modo lectura únicamente, todo registro cargado de esta tabla está bloqueado. Un registro bloqueado no puede guardarse o borrarse desde otro proceso. El modo sólo lectura es el modo recomendado porque autoriza a los otros usuarios a cargar, modificar y luego guardar el registro.
Si una tabla está en modo lectura/escritura, todo registro cargado de esta tabla está desbloqueado sólo si ningún otro usuario ha bloqueado el registro primero. Un registro desbloqueado puede ser modificado y guardado. Una tabla debe ser colocada en modo lectura/escritura antes de que un registro necesite ser cargado, modificado, y luego guardado.
Si el registro debe ser modificado, utilice la función Locked para probar si el registro está bloqueado por otro usuario. Si un registro está bloqueado (Locked devuelve True), cargue el registro con el comando LOAD RECORD pruebe nuevamente si el registro está bloqueado o no. Esta secuencia debe continuar hasta que el registro sea desbloqueado (Locked devuelve False).
Cuando termine las modificaciones a un registro, el registro debe ser liberado (y por lo tanto desbloqueado para los otros usuarios) con UNLOAD RECORD. Si no se libera un registro, permanecerá bloqueado para los otros usuarios hasta que un nuevo registro actual sea seleccionado. Cambiar el registro actual de una tabla desbloquea automáticamente el registro actual anterior. Debe llamar explícitamente a UNLOAD RECORD si no cambia el registro actual. Este principio aplica a los registros existentes. Cuando se crea un nuevo registro, puede guardarse sin importar el estado de la tabla a la cual pertenece.
Nota: cuando se utiliza en una transacción, el comando UNLOAD RECORD descarga el registro actual sólo para el proceso que administra la transacción. Para los otros procesos, el registro permanece bloqueado hasta que la transacción no sea validada (o cancelada).
Utilice el comando LOCKED ATTRIBUTES para ver que usuario y/o proceso tiene bloqueado un registro.
Bucles para cargar registros no bloqueados
El siguiente ejemplo muestra el bucle más simple para cargar un registro no bloqueado:
READ WRITE ([Clientes]) ` Coloca la tabla en modo lectura/escritura Repeat ` Hace un bucle hasta que el registro esté desbloqueado LOAD RECORD ([Clientes]) ` Carga y bloquea el registro Until (Not (Locked([Clientes]))) ` Hacer algo para el registro acá READ ONLY ([Clientes]) ` Coloca la tabla en modo sólo lectura
El bucle continúa hasta que el registro sea desbloqueado.
Un bucle como este se utiliza únicamente cuando es poco probable que el registro esté bloqueado por otra persona, ya que el usuario tendría que esperar hasta que el bucle termine. Este bucle no se utiliza a menos que el registro sólo sea modificable por un método.
El siguiente ejemplo utiliza el bucle anterior para cargar un registro desbloqueado y modificar el registro:
READ WRITE([Inventario]) Repeat ` Bucle hasta que el registro sea desbloqueado LOAD RECORD([Inventario]) ` Cargar el registro y bloquearlo Until (Not (Locked([Inventario]))) [Inventory]Part Qty := [Inventario]Part Qty - 1 ` Modificar el registro SAVE RECORD ([Inventario]) ` Guardar el registro UNLOAD RECORD ([Inventario]) ` Permitir que los otros usuarios lo modifiquen READ ONLY([Inventario])
El comando MODIFY RECORD notifica automáticamente al usuario si un registro está bloqueado y evita que el registro sea modificado. El siguiente ejemplo evita esta notificación automática probando el registro primero con la función Locked. Si el registro está bloqueado, el usuario puede cancelar.
Este ejemplo prueba eficientemente si el registro actual está bloqueado para la tabla [Comandos]. Si está bloqueado, el proceso es retrasado por el método por un segundo. Esta técnica puede utilizarse en un desarrollo multiusuario o multiproceso:
Repeat READ ONLY([Comandos]) ` No necesita lectura/ escritura por el momento QUERY([Comandos]) ` Si la búsqueda se terminó y lo registros son devueltos If ((OK=1) & (Records in selection([Comandos])>0)) READ WRITE([Comandos]) ` Coloque la tabla en modo lectura/escritura LOAD RECORD([Comandos]) While (Locked([Comandos]) & (OK=1)) `Si el registro está bloqueado, ` bucle hasta que el registro sea liberado ` ¿Quién bloqueó el registro? LOCKED ATTRIBUTES([Comandos];$Procesos;$Usuario;$Equipo;$Nombre) If ($Proceso=-1) ` ¿El registro ha sido borrado? ALERT("El registro ha sido borrado en el intervalo.") OK:=0 Else If ($Usuario="") ` ¿Está en modo monusuario? $Usuario:="usted" End if CONFIRM("El registro está siendo utilizado por "+$Usuario+" en el proceso "+$Nombre+" Proceso.") If (OK=1) ` Si quiere esperar algunos segundos DELAY PROCESS(Current process;120) ` Espere algunos segundos LOAD RECORD([Comandos])` Trate de cargar el registro End if End if End while If (OK=1) ` El registro está desbloqueado MODIFY RECORD([Comandos]) ` Puede modificar el registro UNLOAD RECORD([Comandos]) End if READ ONLY([Comandos]) ` Volver a modo sólo lectura OK:=1 End if Until (OK=0)
Uso de comandos en entornos Multi-usuario o Multi-proceso
Ciertos comandos del lenguaje realizan acciones particulares cuando encuentran un registro bloqueado.
Esta es la lista de estos comandos y sus acciones cuando encuentran un registro bloqueado.
MODIFY RECORD: muestra una caja de diálogo indicando que el registro está en uso. El registro no se muestra, por lo tanto el usuario no puede modificarlo. En el entorno Diseño, el registro se muestra en estado sólo lectura.
MODIFY SELECTION: se comporta normalmente excepto cuando el usuario hace doble clic en un registro para modificarlo. MODIFY SELECTION muestra una caja de diálogo indicando que el registro está en uso y luego permite el acceso al registro en modo sólo lectura.
APPLY TO SELECTION: carga un registro bloqueado, pero no lo modifica. APPLY TO SELECTION puede utilizarse para leer información de una tabla sin tener cuidados especiales. Si el comando encuentra un registro bloqueado, el registro se coloca en el conjunto sistema LockedSet.
DELETE SELECTION: no borra los registros bloqueados; simplemente los ignora. Si el comando encuentra un registro bloqueado, el registro se pone en el conjunto sistema LockedSet.
DELETE RECORD: este comando se ignora si el registro está bloqueado. No se devuelve ningún error. Debe probar que el registro está desbloqueado antes de ejecutar este comando.
SAVE RECORD: este comando se ignora si el registro está bloqueado. No se devuelve ningún error. Debe probar que el registro está desbloqueado antes de ejecutar este comando.
ARRAY TO SELECTION: no guarda los registros bloqueados. Si el comando encuentra un registro bloqueado, el registro se pone en el conjunto sistema LockedSet.
GOTO RECORD: en una base multiusuarios/multiprocesos los registros pueden ser añadidos o borrados por otros usuarios, por lo tanto los números de los registros pueden variar. Sea prudente cuando referencie un registro directamente un registro por número en una base multiusuarios.
Conjuntos: sea especialmente cuidadoso con los conjuntos, ya que la información en la que se basa el conjunto puede ser cambiada por otro usuario o proceso.
Ver también
LOAD RECORD, Locked, LOCKED ATTRIBUTES, Métodos, READ ONLY, Read only state, READ WRITE, UNLOAD RECORD, Variables.