Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Como bloquear registros ...

512 views
Skip to first unread message

José Luis Dobón

unread,
Aug 18, 2000, 3:00:00 AM8/18/00
to
    Escribo esto para ver si se clarifican un poco las ideas por ahí, ya que últimamente he visto unas preguntas sobre el tema con unas contestaciones muy poco veraces y que dejaban muy mal sabor de boca.
 
    Es por todos bien sabido los problemas que trae el bloqueo de registros, so pena de que sin bloquear también se tienen problemas. Es por ello que no voy a entrar en polémicas de si se debe o no realizar bloqueos, cada cual sabe qué desarrolla y bajo qué política de empresa trabaja.
 
    Hacendo un poco de memoria, hasta antes del Jet 2.0 el bloqueo se realizaba por páginas de 4 kb cosa que cambió y se quedó en páginas de 2 kb. En el Jet 4.0 (Access 2.000) por temas de carácteres Unicode (cada uno mide 2 bytes) el tamaño ha aumentado de nuevo a páginas de 4 kb. El tamaño de página de SQL Server no sabría asegurarlo (debería mirar mi documentación), pero es parecido. Hasta la versión 7 de SQL Server el bloqueo se realizaba por páginas, en esta versión ya se puede optar al bloqueo a nivel de registro, exactamente igual que el Jet 4.0, en el cual también se pueden realizar bloqueos a nivel de registro (véase en Access 2.000 Herramientas / Opciones / Avanzadas / Abrir bases de datos usando bloqueo por registros )
 
    La técnica para realizar un bloqueo pesimista a nivel de registro difiere para Access y SQL Server. Voy a explicar la forma de realizarlos en ambos usando VB6 con ADO2.5.
 
Cómo bloquear a nivel de registro en bases de datos Access
 
    La base de datos ha de estar en formato Jet 4.0 (Access 2.000), las versiones anteriores sólo soportan bloqueo a nivel de registro y no es suficiente con usar el proveedor Microsoft.Jet.OLEDB.4.0, han de ser ambas cosas. Por defecto Access 2.000 abre las bases de datos con bloqueo a nivel de registro, en contra de cómo lo hace ADO 2.5 y el proveedor Jet 4.0; para ello debemos establecer la propiedad Jet OLEDB:Database Locking Mode en la conexión con el valor 1, además de otros parámetros cómo especificar un nivel de isolación alto y cursores de lado del servidor. Como nota aclaratoria decir que si una aplicación abre la base de datos con nivel de bloqueo por página las siguientes aperturas concurrentes se realizarán con este tipo de bloqueo; así que cuidado.
 
Ejemplo de conexión:
 
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Provider = "Microsoft.Jet.OLEDB.4.0"
cn.Properties("Data Source").Value = "MiBase.mdb"
cn.Properties("Jet OLEDB:Database Locking Mode").Value = 1
 
cn.CommandTimeout = 10             ' Tiempo de espera
cn.CursorLocation = adUseServer
cn.IsolationLevel = adXactChaos
 
cn.Open
 
    Ahora bien, ¿cómo bloqueo un registro? Tan sencillo como abrir una transacción, localizar el registro en cuestión y ponerlo en modo de edición. Para ello deberemos utilizar recordset's en modo pesimista, y cuidado, porque todo lo que modifiquemos durante la transacción quedará bloqueado.
 
Ejemplo de bloqueo
 
    En este ejemplo es un fragmento perteneciente a un mantenimiento de clientes, en este se utilizan dos recordset's: rsClientes sobre el cual previamente se realizó un selección de registros y es por donde se va moviendo el usuario con los botones de movimientos y rsAux que me permite bloquear el registro cuando el usuario pulsa el botón para modificarlo.
 
' Intentar un bloqueo
On Error Resume Next
Bloqueado = False
        
cn.BeginTrans
Set rsAux = New ADODB.Recordset
rsAux.Open SQLClientes & " WHERE IDCliente = " & rsClientes!IDCliente.Value, cn, adOpenKeyset, adLockPessimistic
                
rsAux!NombreComercial.Value = rsAux!NombreComercial.Value
If Err.Number <> 0 And cn.Errors.Count <> 0 Then
   If cn.Errors(0).SQLState = 3218 Or cn.Errors(0).SQLState = 3260 Then
       Bloqueado = True
       rsAux.Close
       Set rsAux = Nothing
       cn.RollbackTrans
   Else
       Err.Raise Err.Number, Err.Source, Err.Description
   End If
Else
   Err.Raise Err.Number, Err.Source, Err.Description
End If
Err.Clear
On Error GoTo 0
        
If Bloqueado Then
   MsgBox "Actualmente este registro está bloqueado por otro usuario.", vbExclamation, Me.Caption
Else
   rsClientes.Resync adAffectCurrent
 
   ' **** Código para modificaciones ó actualizaciones ...
 
    En este ejemplo hay que tener cuidado, ya que aunque rsClientes y rsAux apuntan al mismo registro, el único que podrá modificarlo será rsAux. Nótese que para dejar el registro en modo de edición sólamente hay que igualar cualquier campo a cualquier valor, en este caso igualo el campo NombreComercial a su propio valor (rsAux!NombreComercial.Value = rsAux!NombreComercial.Value).
 
    Lo siguiente a controlar son los errores que vamos a recibir, a saber:
        3218 "Could not update; currently locked": El registro está bloqueado por otro usuario.
        3260 "Couldn't update; currently locked by user <name> on machine <name>": Está bloqueda la página donde se encuentra actualmente el registro.
 
    Adicionalmente otro error a controlar debería ser:
        3197 "The database engine stopped the process because you an another user are attempting to chage de same data at same time"
 
Cómo bloquear a nivel de registro con SQL Server 7.0
 
    En este caso imprescindible SQL Server 7.0 ó superior.
 
Ejemplo de conexión:
 
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Provider = "SQLOLEDB"
cn.Properties("Data Source").Value = "(local)"
cnDatos.Properties("Initial Catalog").Value = "MiBaseDatos"
cnDatos.Properties("User ID").Value = "sa"
cnDatos.Properties("Password").Value = ""
cn.CommandTimeout = 10             ' Tiempo de espera
cn.CursorLocation = adUseServer
cn.IsolationLevel = adXactChaos
 
cn.Open
cnDatos.Execute "SET LOCK_TIMEOUT 0"
 
    Nótese en la sentencia SET LOCK_TIMEOUT, es el tiempo de esperar antes de que SQL Server informe de que un registro está bloqueado, cambiar al gusto (por defecto el valor creo que es bastante alto).
 
    Ahora bien, la forma de bloquear en SQL Server es algo distinta, simplemente hay que seleccionar el registro en un recordset pesimista y ya está, pero cuidado, si el registro está bloqueado por otro usuario nos devolverá un recordset vacío (si la acción hubiera sido un Update en vez de Select entonces sí informaría del bloqueo).
 
Ejemplo de bloqueo
 
    En este ejemplo es un fragmento perteneciente a un mantenimiento de clientes, en este se utilizan dos recordset's: rsClientes sobre el cual previamente se realizó un selección de registros y es por donde se va moviendo el usuario con los botones de movimientos y rsAux que me permite bloquear el registro cuando el usuario pulsa el botón para modificarlo.
 
' Intentar un bloqueo
Bloqueado = False
        
cn.BeginTrans
Set rsAux = New ADODB.Recordset
rsAux.Open SQLClientes & " WHERE IDCliente = " & rsClientes!IDCliente.Value, cn, adOpenKeyset, adLockPessimistic
If rsAux.RecordCount = 0 Then
   rsAux.close
   Set rsAux = Nothing
   Bloqueado = True
End If                 
        
If Bloqueado Then
   MsgBox "Actualmente este registro está bloqueado por otro usuario.", vbExclamation, Me.Caption
Else
   rsClientes.Resync adAffectCurrent
 
   ' **** Código para modificaciones ó actualizaciones ...
 
Notas finales:
 
    Con este mensaje sólo intento clarificar algo sobre el tema, debiendo vosotros investigar a partir de aquí. El código expuesto son fragmentos extraidos de programas y no pueden tener mucho sentido sacados de contexto.
 
Saludos a todos,
 
José Luis Dobón

Antonio Belmonte Campos

unread,
Aug 18, 2000, 3:00:00 AM8/18/00
to
Estupendo análisis. Gracias
 
Antonio Belmonte

Rafael Avendaño Zamorano

unread,
Aug 20, 2000, 3:00:00 AM8/20/00
to
Se puede hacer lo mismo pero dao?
o sea como bloquer un registro con access 2000


de antemano gracias

0 new messages