Actualizar datos
Para actualizar datos, puede usar almacenamiento en búfer, transacciones o vistas.
Realizar actualizaciones con almacenamiento en búfer
Después de elegir el método de almacenamiento en búfer y el tipo de bloqueo, active el almacenamiento en búfer de registros o tablas.
Para activar el almacenamiento en búfer
Elija una de las opciones siguientes:
En el Diseñador de formularios, establezca la propiedad BufferModeOverride del cursor en el entorno de datos del formulario.
–O bien–
En el código, establezca la propiedad Buffering.
Por ejemplo, puede activar el almacenamiento pesimista de filas en búfer si coloca el código siguiente en el procedimiento Init de un formulario:
CURSORSETPROP('Buffering', 2)
Después escriba código para las operaciones de actualización en el código del método apropiado para los controles.
Para escribir las modificaciones en la tabla original, utilice TABLEUPDATE( ). Para cancelar las modificaciones después de una operación errónea de actualización en una tabla restringida por reglas, utilice TABLEREVERT( ). TABLEREVERT( ) es válido aunque el almacenamiento explícito de tablas en búfer no esté activado.
El ejemplo siguiente demuestra cómo actualizar registros cuando está activado el almacenamiento pesimista de registros en búfer.
Ejemplo de actualización mediante búferes de registros y tablas
Código | Comentarios |
---|---|
|
En el código Init del formulario, abre la tabla y activa el almacenamiento pesimista de registros en búfer. |
|
Se desplaza por campos y comprueba los que se han modificado. Nota Este código podría estar en el evento Click de un botón de comando "Guardar" o "Actualizar". |
|
Busca el siguiente registro modificado. |
|
Muestra el valor actual y da al usuario la posibilidad de invertir el cambio del campo actual. |
|
SKIP garantiza que se escribe el último cambio. |
Administrar actualizaciones mediante transacciones
Incluso si utiliza el almacenamiento en búfer pueden surgir problemas. Si desea proteger las operaciones de actualización y recuperar una sección completa de código como una unidad, utilice transacciones.
La incorporación de transacciones a su aplicación proporciona una protección adicional al almacenamiento en búfer de registros y tablas de Visual FoxPro, situando una sección completa de código en una unidad protegida y recuperable. Puede anidar transacciones y emplearlas para proteger actualizaciones almacenadas en búfer. Las transacciones de Visual FoxPro sólo están disponibles con tablas y vistas pertenecientes a una base de datos.
Ajustar segmentos de código
Una transacción actúa como un empaquetador que almacena en memoria caché o en disco las operaciones de actualización de datos, en lugar de aplicar directamente esas actualizaciones a la base de datos. La actualización real de la base de datos se realiza al final de la transacción. Si por alguna razón el sistema no puede realizar las operaciones de actualización en la base de datos, podrá deshacer la transacción completa para que no se lleve a cabo ninguna actualización.
Nota Las operaciones de actualización almacenadas en búfer que se hayan realizado fuera de una transacción se ignoran en otra transacción de la misma sesión de datos.
Comandos que controlan transacciones
Visual FoxPro proporciona tres comandos y una función para administrar una transacción:
Para | Utilice |
---|---|
Iniciar una transacción | BEGIN TRANSACTION |
Determinar el nivel actual de la transacción | TXNLEVEL( ) |
Invertir todos los cambios realizados desde la instrucción BEGIN TRANSACTION más reciente | ROLLBACK |
Bloquear registros, grabar en disco todos los cambios realizados en tablas de la base de datos desde la instrucción BEGIN TRANSACTION más reciente y, a continuación, desbloquear los registros | END TRANSACTION |
Puede utilizar transacciones para ajustar modificaciones de tablas, archivos .cdx estructurales y archivos memo asociados a tablas de una base de datos. Las operaciones en las que intervienen variables y otros objetos no respetan las transacciones, por lo que no se pueden deshacer o confirmar.
Nota Cuando se utilicen los datos almacenados en tablas remotas, el control de los comandos de la transacción sólo actualiza los datos de la copia local del cursor de la vista; las actualizaciones de tablas base remotas no se ven afectadas. Para habilitar las transacciones manuales en tablas remotas, utilice SQLSETPROP( ) y, a continuación, controle la transacción mediante SQLCOMMIT( ) y SQLROLLBACK( ).
En general, deberá utilizar las transacciones con búferes de registro en lugar de almacenamiento de tablas en búfer, salvo para ajustar llamadas de TABLEUPDATE( ). Si incluye un comando TABLEUPDATE( ) en una transacción, podrá deshacer una actualización errónea, resolver la causa del error y, a continuación, volver a intentar TABLEUPDATE( ) sin perder datos. De este modo se asegurará de que la actualización se produce como una operación de "todo o nada".
Aunque el procesamiento simple de transacciones proporciona operaciones seguras de actualización de datos en situaciones normales, no ofrece protección total contra errores del sistema. Si se interrumpe el suministro eléctrico o el sistema queda bloqueado durante el procesamiento del comando END TRANSACTION, se puede producir un error en la actualización de datos.
Utilice el código siguiente como plantilla para transacciones:
BEGIN TRANSACTION
* Update records
IF lSuccess = .F. && an error occurs
ROLLBACK
ELSE && commit the changes
* Validate the data
IF && error occurs
ROLLBACK
ELSE
END TRANSACTION
ENDIF
ENDIF
Usar transacciones
Las reglas siguientes se aplican a las transacciones:
- Una transacción comienza con el comando BEGIN TRANSACTION y termina con el comando END TRANSACTION o ROLLBACK. Una instrucción END TRANSACTION que no vaya precedida de una instrucción BEGIN TRANSACTION generará un error.
- Una instrucción ROLLBACK que no vaya precedida de una instrucción BEGIN TRANSACTION generará un error.
- Una vez comenzada una transacción, permanecerá en vigor hasta que comience el END TRANSACTION correspondiente (o hasta que se ejecute un comando ROLLBACK), incluso en programas y funciones, a menos que se termine la aplicación, lo que producirá una anulación.
- Visual FoxPro utiliza datos almacenados en caché en el búfer de transacciones antes de utilizar datos del disco para consultas acerca de los datos relacionados con transacciones. De este modo se asegura la utilización de los datos más actuales.
- Si la aplicación termina durante una transacción, todas las operaciones se desharán.
- Una transacción sólo funciona en un contenedor de base de datos.
- No es posible utilizar el comando INDEX si sobrescribe un archivo de índice existente o si hay abierto algún archivo de índice .cdx.
- Las transacciones pertenecen al ámbito de las sesiones de datos.
Las transacciones presentan los comportamientos de bloqueo siguientes:
- En una transacción, Visual FoxPro impone un bloqueo en el momento en que un comando lo solicita directa o indirectamente. Cualquier comando de desbloqueo directo o indirecto procedente del sistema o del usuario se almacena en caché hasta que se complete la transacción mediante los comandos ROLLBACK o END TRANSACTION.
- Si utiliza un comando de bloqueo como FLOCK( ) o RLOCK( ) en una transacción, la instrucción END TRANSACTION no liberará el bloqueo. En ese caso, deberá desbloquear explícitamente todos los bloqueos realizados en una transacción. Las transacciones que contienen los comandos FLOCK( ) o RLOCK( ) deben ser lo más breves posible; en caso contrario, los usuarios podrían encontrar los registros bloqueados durante mucho tiempo.
Anidar transacciones
Las transacciones anidadas proporcionan grupos lógicos de operaciones de actualización de tablas que están aislados de los procesos concurrentes. No es necesario que los pares BEGIN TRANSACTION...END TRANSACTION estén en la misma función o el mismo procedimiento. Las transacciones anidadas tienen estas reglas:
- Se pueden anidar hasta cinco pares BEGIN TRANSACTION...END TRANSACTION.
- Las actualizaciones realizadas en una transacción anidada no se confirman hasta que se llama a la instrucción END TRANSACTION más externa.
- En las transacciones anidadas, una instrucción END TRANSACTION sólo funciona sobre la transacción iniciada por la última instrucción BEGIN TRANSACTION ejecutada.
- En las transacciones anidadas, una instrucción ROLLBACK sólo funciona sobre la transacción iniciada por la última instrucción BEGIN TRANSACTION ejecutada.
- La actualización más interna de una serie de transacciones anidadas sobre los mismos datos tiene prioridad sobre todas las demás del mismo bloque de transacciones anidadas.
Observe en el ejemplo siguiente que, puesto que los cambios en una transacción anidada no se escriben en disco, sino en el búfer de transacciones, la transacción más interna sobrescribirá los cambios realizados en los mismos campos STATUS de la transacción anterior:
BEGIN TRANSACTION && transaction 1
UPDATE EMPLOYEE ; && first change
SET STATUS = "Contract" ;
WHERE EMPID BETWEEN 9001 AND 10000
BEGIN TRANSACTION && transaction 2
UPDATE EMPLOYEE ;
SET STATUS = "Exempt" ;
WHERE HIREDATE > {^1998-01-01} && overwrites
END TRANSACTION && transaction 2
END TRANSACTION && transaction 1
El siguiente ejemplo de transacción anidada elimina un registro de cliente y todas las facturas relacionadas. La transacción se deshará si se producen errores durante un comando DELETE. Este ejemplo demuestra la agrupación de operaciones de actualización de tablas para impedir que las actualizaciones se completen parcialmente y para evitar conflictos de simultaneidad.
Ejemplo de modificación de registros en transacciones anidadas
Código | Comentarios |
---|---|
|
Limpia el entorno de otras transacciones. |
|
Establece el entorno para el almacenamiento en búfer. |
|
Activa el almacenamiento optimista de tablas en búfer. |
|
Cambia un registro. Cambia otro registro. |
|
Inicia la transacción 1 e intenta actualizar todos los registros modificados que no están vigentes. |
|
Si se producen errores en la actualización, deshace la transacción. Obtiene un error de AERROR( ). Determina la causa del error. Si un desencadenador ha producido errores, soluciona el problema. Si un campo no acepta valores nulos, soluciona el problema. Si se ha infringido una regla de campo, soluciona el problema. |
|
Si otro usuario ha modificado un registro, localiza el primer registro modificado. Hace un bucle a través de todos los registros modificados, comenzando con el primero. Bloquea cada registro para asegurarse de que se puede actualizar. Comprueba si hay cambios en cada campo. Compara el valor almacenado en búfer con el valor en disco; a continuación, muestra un cuadro de diálogo al usuario. |
|
|
|
Si el usuario responde "No", invierte el registro uno y lo desbloquea. |
|
Sale del bucle "FOR nField...". |
|
Obtiene el siguiente registro modificado. |
|
Inicia la transacción 2 y actualiza todos los registros no invertidos que están en vigor. Finaliza la transacción 2. Libera el bloqueo. |
|
Si el registro está en uso por otro usuario, soluciona el problema. Si se ha infringido una regla de fila, soluciona el problema. Si hubo una infracción de índice único, soluciona el problema. De lo contrario, muestra un cuadro de diálogo al usuario. |
|
Termina la transacción 1. |
Proteger actualizaciones remotas
Las transacciones pueden protegerle frente a los errores generados por el sistema durante actualizaciones de datos en tablas remotas. El ejemplo siguiente utiliza una transacción para ajustar operaciones de escritura de datos en una tabla remota.
Ejemplo de una transacción de una tabla remota
Código | Comentarios |
---|---|
|
Obtiene el controlador de conexión y activa transacciones manuales. |
|
Comienza la transacción manual. |
|
Intenta actualizar todos los registros que no están en vigor. Si la actualización ha producido errores, deshace la transacción en la conexión del cursor. |
|
Obtiene un error de AERROR( ). |
|
Si un desencadenador ha producido errores, soluciona el problema. |
|
Si un campo no acepta valores nulos, soluciona el problema. |
|
Si se ha infringido una regla de campo, soluciona el problema. |
|
Si otro usuario ha cambiado un registro, soluciona el problema. Hace un bucle a través de todos los registros modificados, comenzando con el primero. |
|
Comprueba si hay cambios en cada campo. Compara el valor almacenado en búfer con el valor del disco y, a continuación, muestra un cuadro de diálogo al usuario. |
|
Si el usuario respondió "No", invierte el registro uno. Sale del bucle "FOR nField...". Obtiene el siguiente registro modificado. |
|
Actualiza todos los registros no invertidos que están vigentes y ejecuta una confirmación. |
|
El error 109 indica que otro usuario está utilizando el registro. |
|
El error 1583 indica que se ha infringido una regla de la fila. |
|
El error 1884 indica que se ha infringido la unicidad del índice. |
|
|
|
Muestra un cuadro de diálogo al usuario. Fin del control de errores. |
|
Si se controlaron todos los errores y la transacción completa se ha realizado con éxito, ejecuta una confirmación y termina la transacción. |
Vea también
Almacenar datos en búfer | Administrar el rendimiento | Programar para acceso compartido | TABLEUPDATE( ) | TABLEREVERT( ) | Controlar el acceso a datos | Administrar conflictos