versión 11 (Modificado)
Las transacciones son una serie de modificaciones efectuadas al interior de un proceso sobre datos relacionados. Una transacción no se guarda permanente en la base hasta que la transacción sea validada. Si no se completa una transacción, bien sea porque se cancela o por un evento externo, las modificaciones no se guardan.
Durante una transacción, todos los cambios realizados a los datos de la base dentro del proceso se almacenan localmente en un buffer temporal. Si la transacción se acepta con VALIDATE TRANSACTION, los cambios se guardan de manera permanente. Si la transacción se cancela con CANCEL TRANSACTION, los cambios no se guardan. En todos los casos, ni la selección actual ni el registro actual son modificados por los comandos de gestión de transacciones.
A partir de la versión 11, 4D soporta transacciones anidadas, es decir, transacciones en varios niveles jerárquicos. El número de subtransacciones autorizadas es ilimitado. El comando Transaction level permite conocer el nivel actual de transacción en el cual se ejecuta el código.
Cuando utiliza transacciones anidadas, el resultado de cada subtransacción depende de la validación o cancelación de la transacción de nivel superior. Si se valida la transacción de nivel superior, los resultados de las subtransacciones se confirman (validación o cancelación). Por el contrario, si la transacción superior se cancela, todas las subtransacciones se cancelan, sin importar sus resultados.
Opción compatibilidad
Las transacciones anidadas pueden generar disfunciones en las bases desarrolladas con versiones anteriores de 4D, por esta razón está opción está desactivada por defecto en las bases convertidas (las transacciones quedan limitadas a un solo nivel). Si quiere aprovechar las transacciones en varios niveles en una base convertida, debe indicarlo explícitamente seleccionando la opción Permitir transacciones anidadas en la página "Aplicación/Compatibilidad" de las Preferencias de la aplicación.
Esta opción aparece únicamente en bases de datos convertidas. Por defecto, no está seleccionada y es especifica para cada base. No tiene efecto en las transacciones efectuadas en el motor SQL de 4D. Las transacciones SQL siempre son multinivel.
Ejemplos de transacciones
En este ejemplo, la base es una sistema de facturación simple. Las líneas de las facturas son almacenadas en una tabla llamada [Linea_Factura], la cual está relacionada con la tabla [Facturas] por una relación entre los campos [Facturas]NoFacturas y [Linea_Factura]NoFacturas. Cuando se añade una factura, se calcula un número único, utilizando el comando Sequence number. La relación entre [Facturas] y [Linea_Factura] es una relación automática Muchos a Uno. La casilla de selección Autoasignar valor en el subformulario está seleccionada.
La relación entre [Linea_Factura] y [Partes] es manual.
Cuando un usuario introduce una factura, se ejecutan las siguientes acciones:
Adición de un registro en la tabla [Facturas].
Adición de varios registros en la tabla [Linea_Factura].
Actualización del campo [Partes]En_Bodega de cada parte listada en la factura.
Este ejemplo es una situación típica en la cual necesita utilizar una transacción. Debe asegurarse de poder guardar todos estos registros durante la operación o de que poder cancelar la transacción si un registro no puede añadirse o actualizarse. En otras palabras, debe guardar los datos relacionados.
Si no utiliza una transacción, no puede garantizar la integridad de datos lógica de su base. Por ejemplo, si un registro de la tabla [Partes] está bloqueado, no podrá actualizar la cantidad almacenada en el campo [Partes]En_Bodega. Este campo se volverá entonces lógicamente incorrecto. La suma de las partes vendidas y restantes en bodega no será igual a la cantidad original introducida en el registro. Puede evitar tal situación utilizando las transacciones.
Hay varias maneras de introducir datos utilizando transacciones:
1. Puede administrar las transacciones utilizando los comandos de transacción START TRANSACTION, VALIDATE TRANSACTION, y CANCEL TRANSACTION. Puede escribir, por ejemplo:
READ WRITE([Linea_Factura]) READ WRITE([Partes]) INPUT FORM([Facturas];"Entrada") Repeat START TRANSACTION ADD RECORD([Facturas]) If (OK=1) VALIDATE TRANSACTION Else CANCEL TRANSACTION End if Until (OK=0) READ ONLY(*)
2. Para reducir los bloqueos de registros durante la entrada de datos, puede también seleccionar administrar transacciones a partir del método de formulario y acceder a las tablas en READ WRITE únicamente cuando sea necesario.
Usted efectúa la entrada de datos utilizando el formulario de entrada para [Facturas], el cual contiene la tabla relacionada [Facturas]Lineas en un subformulario. El formulario tiene dos botones: bCancel y bOK, ambos son botones sin acciones.
El bucle de adición se convierte en:
READ WRITE([Linea_Factura]) READ ONLY([Partes]) INPUT FORM([Facturas];"Entrada") Repeat ADD RECORD([Facturas]) Until (bOK=0) READ ONLY([Linea_Factura])
Note que la tabla [Partes] está en modo de acceso "sólo lectura" durante la entrada de datos. El acceso lectura/escritura estará disponible únicamente si los datos se validan.
La transacción se abre en el método de formulario de entrada de la tabla [Facturas]:
Case of : (Form event=On Load) START TRANSACTION [Facturas ]NoFacturas:=Sequence number([Facturas ]NoFacturas) Else [Facturas]Total_Factura:=Sum([Linea_Factura]Total_Linea) End case
Si hace clic en el botón bCancel, la entrada y la transacción deben ser canceladas.
Este es el método de objeto del botón bCancel:
Case of : (Form event=On Clicked) CANCEL TRANSACTION CANCEL End case
Si hace clic en el botón bOK, la entrada y la transacción deben ser aceptadas. Este es el método de objeto del botón bOK:
Case of : (Form event=On Clicked) $NbLineas:=Records in selection([Linea_Factura]) READ WRITE([Partes]) ` Cambiar a acceso lectura/escritura para la tabla [Partes] FIRST RECORD([Linea_Factura]) ` Iniciar en la primera línea $ValidTrans:=True ` Asume que todo estará OK For ($Line;1;$NbLines) ` Para cada línea RELATE ONE([Linea_Factura]NoParte) OK:=1 ` Asume que usted quiere continuar While (Locked([Partes]) & (OK=1)) ` Tratar de obtener el registro en acceso Lectura/Escritura CONFIRM("La parte "+[Linea_Factura]NoParte+" está en uso. ¿Espera?") If (OK=1) DELAY PROCESS(Current process;60) LOAD RECORD([Partes]) End if End while If (OK=1) ` Actualizar cantidad en la bodega [Partes]En Bodega:=[Partes]En Bodega-[Linea_Factura]Cantidad SAVE RECORD([Partes]) ` Guardar registro Else $Linea:=$NbLineas+1 ` Dejar el bucle $ValidTrans:=False End if NEXT RECORD([Linea_Factura]) ` Ir a la siguiente línea End for READ ONLY([Partes]) ` Definir el estado de la tabla en modo sólo lectura If ($ValidTrans) SAVE RECORD([Facturas]) ` Guarda el registro Facturas VALIDATE TRANSACTION ` Validar todas las modificaciones a la base Else CANCEL TRANSACTION ` Cancelar todo End if CANCEL ` Dejar el formulario End case
En este código, llamamos al comando CANCEL sin importar en cual botón el usuario haga clic. El nuevo registro no está validado por una llamada a ACCEPT, pero por el comando SAVE RECORD. Además, note que SAVE RECORD se llama justo antes que el comando VALIDATE TRANSACTION. Por lo tanto, guardar el registro [Facturas] es en realidad parte de la transacción. Llamar el comando ACCEPT también validaría el registro, pero en este caso la transacción será validada antes de que el registro [Facturas] se guarde. En otras palabras, el registro sería guardado fuera de la transacción.
Dependiendo de sus necesidades, puede personalizar su base, como se muestra en estos ejemplos. En el último ejemplo, la gestión de bloqueo de registros de la tabla [Partes] puede desarrollarse más.
Ver también
CANCEL TRANSACTION, In transaction, START TRANSACTION, VALIDATE TRANSACTION.