Está en la página 1de 10



Dirección General de Servicios de Cómputo Académico


Dirección de Cómputo para la Docencia

CURSO: Lenguaje de Programación Visual Basic (Avanzado)


INSTRUCTOR: L.I. Raymundo Lumbreras López

Nombre del participante: __________________________________________________________________

Práctica No. 9

Objetivo: El participante implementará una aplicación en donde podrá experimentar con las transacciones propias
del manejo de una base de datos, y también realizará bloqueos a los registros de las tablas.

Instrucciones: Diseñe la interfaz que se muestra, respete los prefijos sugeridos para los objetos. inserte los objetos
que se muestran, modifique propiedades e inserte el código correspondiente.

Desarrollo:

Transacciones
Pensemos en un ejemplo de transacciones que se realizan con frecuencia en los entornos bancarios. Por
ejemplo, una transferencia de dinero entre dos cuentas implica por un lado una reducción del saldo de la
cuenta de origen y por otro lado un aumento de la cuenta de destino.

Pueden darse situaciones en las que, bien sea por errores de hardware, bien sea por inexistencia de fondos
o por parte del saldo de una cuenta que está inmovilizado (Cheques en transito por ejemplo), la transacción
que implica los dos movimientos debe deshacerse y todas las cuentas involucradas en la transacción deben
volver al estado que tenían antes de iniciarse dicha operación.

Desde la versión 4.0 de Visual Basic los métodos aplicables a las transacciones (BeginTrans,
CommitTrans y RollBack) se aplican al objeto WorkSpace de los objetos DAO.

En la mayor parte de los servidores, las transacciones mantienen bloqueos de registros cuya finalidad es
evitar que otros usuarios puedan modificar e incluso leer los datos modificados por una transacción hasta
que dicha transacción sea confirmada (CommitTrans) o revocada (RollBack).

Por lo tanto para evitar en lo posible estos bloqueos, deberemos poner algo de nuestra parte; no mantener
una transacción pendiente durante demasiado tiempo, ya que ese tiempo puede ser precioso para el resto
de los usuarios que desean acceder a registros que nosotros estamos modificando.

En este ejemplo vamos a ver cómo podemos utilizar los WorkSpaces para lanzar transacciones en Visual
Basic entre dos cuentas bancarias. En la primera operación realizaremos una resta de la primera cuenta,
mientras que en la segunda operación aumentaremos el saldo de la segunda cuenta.

Si cualquiera de las dos operaciones falla revocaremos la transacción.

Hoja [1] de[10]




Base de Datos: Banco

Tabla: Cuentas
Nombre Tipo Tamaño Regla de Validación
IDCuenta Numérico Entero Largo
Titular Texto 40
Saldo Numérico Doble >0

Tabla: Movimientos
Nombre Tipo Tamaño
IDCuentaOrigen Numérico Entero Largo
IDCuentaDestino Numérico Entero Largo
Cantidad Numérico Doble
FechaHora Fecha/Hora
Concepto Texto 50

En la tabla de cuentas introducimos los datos de dos registros de prueba. Por ejemplo:

IDCuenta Titular Saldo


1001 Rosario Robles 1000
1002 Cuauhtemoc Cárdenas 1000

Tranferiremos varias veces 100 pesos desde la cuenta 1001 hacia la cuenta 1002. Al llegar a saldo cero en la
primera cuenta no se deberá incrementar la segunda, ya que no hay saldo físico en la primera cuenta.

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [2] de[10]


Utilizaremos el siguiente código fuente dentro de un botón de comando:

Private Sub Command1_Click()


ChDir App.Path
Dim ws1 As Workspace, Banco As Database
Dim qdfTransferencia As QueryDef

On Error GoTo FalloTransferencia


Screen.MousePointer = 11
Set ws1 = DBEngine.Workspaces(0)
Set Banco = ws1.OpenDatabase("banco.mdb")

' Empieza la primera parte de la transacción


ws1.BeginTrans
ComandoSQL$ = "UPDATE Cuentas SET Saldo = Saldo - 100 WHERE IDCuenta = 1001"
'Restamos 100 de la primera cuenta
Banco.Execute ComandoSQL$, dbFailOnError

'Segunda parte de la transacción


ComandoSQL$ = "UPDATE Cuentas SET Saldo = Saldo + 100 WHERE IDCuenta = 1002"
'Añadimos 100 a la segunda cuenta
Banco.Execute ComandoSQL$, dbFailOnError

ComandoSQL$ = "INSERT INTO Movimientos " & "(IDCuentaOrigen, IDCuentaDestino, Cantidad, FechaHora,
Concepto) VALUES (1001, 1002, 100,#" + CStr(Now) + "#, 'Transferencia')"
Banco.Execute ComandoSQL$, dbFailOnError

'Si hemos llegado hasta aquí quiere decir


'que todo ha ido bien y por tanto debemos
'confirmar la transacción
ws1.CommitTrans
'Cerrar la base de datos
Banco.Close
Screen.MousePointer = 0
Exit Sub
'Si algo falla, irá a parar aquí:
FalloTransferencia:
Screen.MousePointer = 0
MsgBox Error$, vbOKOnly, "Cancelamos la transacción"
'Cancelar la transacción:
ws1.Rollback
Exit Sub
End Sub

AL trangredirse la norma de que el saldo de la cuenta origen debe ser superior a cero, aparecerá el siguiente
mensaje de la aplicación:

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [3] de[10]


Acceso Multiusuario
En toda Base de datos en la que operan simultáneamente varios usuario se da el problema del acceso
concurrente a la información. Por ejemplo, imaginemos que dos usuarios están accediendo a la vez al mismo
registro para modificarlo. Si ese registro contiene información sobre el precio de un producto, ¿Qué sucederá
tras ambas modificaciones¿

Hace años, determinadas aplicaciones pensadas para el funcionamiento monousuario llegaban hasta extremos
de bloquear la máquina cuando dos usuarios accedían al mismo registro. Ese era el caso de aplicaciones
escritas en las primeras versiones de Basic o de Borland Turbo Pascal para el sistema operativo MSDOS 2.0 y
con las modificaciones de sistema de MultiLink. En dichas aplicaciones, en las que no se contemplaba el
problema multiusuario, al realizarse la escritura al mismo tiempo, el sistema operativo entraba en un
deadlock( Bloqueo de máquina de tipo bucle infinito que no reacciona al teclado) dejando de atender a los
usuarios.

Una vez que los compiladores y el sistema operativo MSDOS contemplaron el tema de las interrupciones de
NetBIOS y la instrucción SHARE para compartir archivos, el problema del acceso multiusuario quedó reducido
a un tema de coherencia de base de datos.

La coherencia o congruencia se limita a formular en la práctica este tipo de preguntas: ¿Cuál es el resultado de
un listado en el que uno de sus registros está siendo borrado por uno de los usuarios? ¿De qué sirve modificar
el precio de un producto si antes de grabarlo otro usuario ha dado de baja dicho producto? ¿Se debería permitir
que mientras un usuario edita un registro otro usuario esté modificándolo?

La herramienta que puede ayudarnos a evitar que se produzcan estos casos es el bloqueo. La idea que anima
el concepto del bloqueo es la misma que la de la propiedad privada. En el momento en que un usuario edita un
registro, el registro pasa a ser propiedad del usuario. En el momento en que el usuario escribe el registro
modificado, libera su propiedad y otro usuario diferente puede apropiarse de la información ya modificada.

No debemos confundir bloqueo con la validez de los datos. Los datos siempre son válidos, independientemente
de si están o no bloqueados.

• El usuario Jorge edita un registro de un cliente para grabar un contenido diferente. Una vez que los datos
están en pantalla, decide ir a tomar un café.

• La usuario Dolores quiere leer el registro para saber la dirección del cliente pero no desea modificar los
datos. ¿Deberá esperar a que regrese Jorge? No!, utilizando SanpShot podrá accesar la información sin
esperar a que se retire el bloqueo.

• Un tercer usuario, Gonzalo, desea realizar una factura para ese mismo cliente que Jorge, inadvertidamente,
ha dejado bloqueado en su terminal de trabajo. Ya que la factura actualiza el campo de total de ventas del
cliente Gonzalo deberá esperar a que se retire el bloqueo.

Bloque optimista y pesimista


EL comportamiento que acabamos de describir es el bloqueo pesimista, el cuál se establece desde el momento
en que llamamos a la instrucción Edit. Hasta el momento en que lo liberamos mediante la instrucción Update.

En cambio el bloqueo optimista se realiza justo durante el tiempo que dura la escritura del Update. Esto quiere
decir que si deseamos evitar distracciones por parte de los usuarios que puedan llegar a mantener una base de
datos bloqueada mientras toman café, deberemos emplear este método.

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [4] de[10]


Este tipo de bloqueo se establece mediante la instrucción LockEdits. Por defecto está en modo pesimista
(LockEdits = True) aunque por programa podemos establecer que sea optimista (LockEdits = False)

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [5] de[10]


Construiremos una aplicación de bloqueo de registros basada en un DataControl en al que forzaremos el


bloqueo de registro por programa cada vez que vayamos a modificar su contenido.

Private Sub Command1_Click()


Data1.Recordset.Edit
Text1.Enabled = True
Text2.Enabled = True
Data1.Enabled = False
Text1.SetFocus
End Sub
Private Sub Command2_Click()
On Error GoTo err_grabar
Data1.Recordset.Update
Text1.Enabled = False
Text2.Enabled = False
Data1.Enabled = True
Exit Sub
err_grabar:
j% = MsgBox(Error$, 0, "Mensaje de Error:")
Resume Next
End Sub

Gurdemos el proyecto y crearemos el ejecutable:

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [6] de[10]


Ejecutemos dos veces el proyecto para tener dos instancias del mismo.

Una vez que en ambas aplicaciones tengamos por ejemplo el autor No. 4, pulsaremos en una de ellas el botón
bloquear para modificar. Esto nos validará las cajas de texto. Intentemos ahora el mismo registro en la otra
aplicación. Nos mostrará el mensaje de error:

Tras aparecer el mensaje de error, la aplicación se cerrará. Esto es lo que puede suceder si lo ejecutamos en
red y no colocamos el mecanismo de manejo de errores. Vamos a instroducir cambios al código para que pueda
manejar la cricunstancia de un bloqueo previo:

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [7] de[10]


Private Sub Command1_Click()


On Error GoTo bloqueo_error:
Data1.Recordset.Edit
Text1.Enabled = True
Text2.Enabled = True
Data1.Enabled = False
Text1.SetFocus
salir:
Exit Sub
bloqueo_error:
j% = MsgBox(Error$, 0, "Mensaje de Error:")
Resume salir
End Sub

Ahora aparece un mensaje casí idéntico y el programa no se cierra como en el caso anterior

Escribiremos un proceso de manejo de error. EL método utilizado será el de extraer el nombre del usuario del
interior de la cadena de mensaje de error. Obviaremos el nombre de la máquina.

Sub Procesa(MensError$)
PosInicial% = 43
PosFinal% = InStr(MensError$, "on machine")
Usuario$ = Mid$(MensError$, PosInicial%, PosFinal% - PosInicial%)
MensajeNuevo$ = "El Usuario " + Usuario$ + " Esta Bloqueando el Registro"
MsgBox (MensajeNuevo$)
End Sub

El nombre de la máquina solo aparece cuando nuestra computadora pertenece a un grupo de trabajo. Pese a
ello, los bloqueos de registros funcionan siempre, garantizando la congruencia de los datos en el caso en que
incluso varias tareas dentro de una computadora monousuaria accedan al concurrentemente a los mismos
datos. De este modo, en el código fuente del botón de bloqueo y modificación haremos los siguientes cambios

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [8] de[10]


Private Sub Command1_Click()


On Error GoTo bloqueo_error:
Screen.MousePointer = 11 'Reloj de Arena
Data1.Recordset.Edit
Text1.Enabled = True
Text2.Enabled = True
Data1.Enabled = False
Text1.SetFocus
salir:
Screen.MousePointer = 0 'Restaurar valor
Exit Sub
bloqueo_error:
If Err = 3260 Then 'Error debido a bloqueo
MensError$ = Error$
Procesa (MensError$)
Else
j% = MsgBox(Error$, 0, "Mensaje de Error:")
End If
Resume salir
End Sub

Y podremos ver el siguiente mensaje de error ya modificado por el código anterior mediante el proceso Procesa.

Bloqueos por pagina


Uno de los principales inconvenientes de Visual Basic en el tema de bloqueos de bases de datos es que no
realiza un bloqueo de registro puro. Cuando bloqueamos sobre un registro, lo que estamos haciendo realmente
es bloquear un área de 2048 bytes alrededor del registro. Este tamaño de 2048 bytes es el que se conoce como
página.

Esta es una seria limitación de diseño del motor de Access y también de Microsoft SQL Server, el cual por
defecto realiza el bloqueo por páginas.

Si nuestro registro tiene una longitud de 2 Kbytes, el bloqueo de registro será igual al bloqueo por página, pero
si nuestro registro tuviera una longitud de 200 bytes, en una sola operación de edición bloquearíamos 10
registros consecutivos aproximadamente.

• Muchos problemas de lentitud de acceso se deben realmente al tiempo de reintento en las operaciones de
lectura y escritura multiusuario. Para mejorar este tiempo de acceso, debemos utilizar siempre que sea
posible SnapShots en lugar de DynaSets.

• Una transacción que realice una operación DELETE en SQL, por ejemplo, bloqueará todos los registros
afectados antes de borrarlos, en el momento que se realice un CommitTrans o un RollBack se liberarán.

Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [9] de[10]


Curso: Lenguaje de Programación Visual Basic Avanzado. Práctica 9


Instructor: L.I. Raymundo Lumbreras López Hoja [10] de[10]

También podría gustarte