Usuarios conectados a base de datos Access – User Roster

Usuarios Conectados

Si alguna vez habéis desarrollado una aplicación multiusuario en Access, sabréis que una de las dificultades de no utilizar otro tipo de plataformas más orientadas a cliente-servidor (Sql Server, Oracle, etc) viene a la hora de realizar modificaciones en el Backend de nuestra aplicación (ver artículo sobre Dividir bases de datos Access).

Cuando hacemos cambios de diseño en una base de datos Access, necesitamos tener acceso exclusivo al objeto que vamos a modificar, así que si tenemos algún usuario conectado a la base de datos, no podremos realizarlos. Cuando hablo de cambios de diseño, me refiero sobre todo a cambios en tablas y relaciones ya que normalmente los backends no deben tener otro tipo de objetos (tal vez pueden llevar alguna macro y algo de código, pero el resto debería estar en los frontends cliente).

Tal vez penséis que este tipo de cambios no se realizan habitualmente, pero la idea de base de datos estática desapareció de mi cabeza hace años. Siempre hay alguna nueva funcionalidad que necesita tablas nuevas, algún atributo nuevo de una tabla, etc. Además, hay otro tipo de operaciones de administración de una base de datos que también necesitan el acceso exclusivo, la más utilizada la herramienta para compactar y reparar la base de datos.

Suelo compactar y reparar los backends de mis aplicaciones por lo menos 1 vez por semana (a veces se producen herrores y hay que hacerlo sobre la marcha) y como vemos en la propia web de Microsoft:

Si va a compactar una base de datos compartida de Microsoft Access que está ubicada en un servidor o en una carpeta compartida, asegúrese de que ningún otro usuario la tiene abierta.

No podría contar la de veces que he tenido que enviar decenas de mails a los usuarios de uno de mis desarrollos para avisar de que se iban a realizar tareas de mantenimiento. Generalmente el usuario es una persona obediente y se desconecta el tiempo que sea necesario, pero no se por qué, siempre quedan varios conectados. Es entonces cuando te pasas los minutos mirando el archivo de bloqueo (laccdb en las nuevas versiones) y llamando por teléfono a los responsables de cada oficina. Nunca se descubre al culpable y acabas quedándote después de trabajar para realizar las modificaciones (o para por lo menos bloquear la base de datos…). Otra posibilidad es entrar media horita antes que tus usuarios (no me suele funcionar y menos ahora que soy padre primerizo).

Por todo esto, hace tiempo que utilizo un Administrador de Usuarios que me permite seleccionar una base de datos Access (backend) y ver los usuarios que hay conectados. Hasta ahora utilizaba un recordset esquema User Roster de ADO. Este tipo de esquema guarda en el recordset ciertos datos de los usuarios que están conectados a la base de datos que le indiques:

  • Nombre de Equipo: Ordenador desde el que se conecta
  • Usuario: Usuario de Access (a partir de Access 2007 siempre será Admin al desaparecer la seguridad a nivel de usuario)
  • Conectado (si/no): Si el usuario se encuentra conectado en ese momento.Si es no conectado, posible archivo corrupto. Compactar y reparar base de datos
  • Estado: Nulo a no ser que se haya cerrado de una manera no habitual. Compactar y reparar base de datos

Con estos datos es bastante complicado saber quien es en realidad el usuario que está conectado, pero por lo menos podemos saber cuantos son e investigando un poco descubriremos la manera de desconectarlos.

Desde que diseñé este primer adminstrador de usuarios, lo he modificado mucho y actualmente tiene muchas más funcionalidades. Por ello he decidido colgar la aplicación Adminstración de Usuarios e ir explicando y publicando los pasos que he seguido para desarrollar cada versión (y compartiendo el código).

En este artículo voy a explicar como llegué en su día a esa primera versión que por lo menos me permitía “monitorizar” los usuarios que están conectados a una base de datos y más adelante iré añadiendo nuevas funcionalidades (podéis ir revisando la sección de la aplicación de Administración y desconexión de usuarios de bases de datos Access para ver el estado en el que se encuentra en cada momento).

Como ya sabéis, no soy muy fan de ADO pero en este caso nos ofrece la posibilidad de abrir recordsets de esquemas que son muy interesantes, en nuestro caso utilizaremos JET_SCHEMA_USERROSTER, como he comentado anteriormente. El procedimiento es bastante sencillo:

Declaramos las variables que vamos a utilizar:

Dim Conexion As New ADODB.Connection     'Para crear la conexión. Tengo que utilizar ADO, aunque no me guste
Dim rsConexiones As New ADODB.Recordset  'Para la tabla que tendrá las conexiones
Dim schemaID As String
'**********************************************************************
'En nuestro caso utilizamos JET_SCHEMA_USERROSTER -> {947bb102-5d43-11d1-bdbf-00c04fb92675}
schemaID = "{947bb102-5d43-11d1-bdbf-00c04fb92675}"
'**********************************************************************

Asignamos el proveedor aunque a partir de Access 2007 es Microsoft ACE OLEDB 12.0

Conexion.Provider = CurrentProject.Connection.Provider 'Por si acaso asignamos el proveedor aunque se supone que será Microsoft ACE OLEDB 12.0

La siguiente funcionalidad la añadí cuando empecé a encriptar las bases de datos con contraseña, se le pasa la contraseña a la cadena de conexión:

Conexion.Properties("Jet OLEDB:Database Password") = "Contraseña del Backend"

Y finalmente abrimos la conexión y creamos el recordset:

Conexion.Open "Data Source=ruta_al_backend"
Set rsConexiones = Conexion.OpenSchema(schema:=adSchemaProviderSpecific, schemaID:=schemaID) ' Conexión sacada de la web de Microsoft

Con estos pasos tendremos un recordset llamado rsConexiones con los datos de conexión de cada uno de nuestros usuarios conectados. Podemos por ejemplo guardarlos en una tabla y luego crear un formulario con un cuadro de lista que tenga como origen esa tabla.

Para ponerlo más sencillo, os paso una función a la que le pasas la ruta del backend (parámetro que llamaré Fichero) y la contraseña en caso de tenerla (parámetro Contraseña) y te llena una tabla (en nuestro ejemplo la llamo “CONEXIONES”) con los datos de nuestros usuarios.

'*************************************************************************************************************************************
'Autor: Arkaitz Arteaga
'Más artículos: www.programadordepalo.com
'Mail de contacto: admin@programadordepalo.com
'Fecha: Enero 2014
'Version: 1.0
'*************************************************************************************************************************************
    'Sacado de la web de Microsoft (necesario Microsoft ActiveX Data Objects 2.x Library)
    ' Para abrir connection.OpenSchema(querytype, criteria, schemaID)
    ' schemaID -> Hay diferentes tipos, en este caso utilizaremos JET_SCHEMA_USERROSTER -> {947bb102-5d43-11d1-bdbf-00c04fb92675}
    '-Nombre del equipo que está utilizando el usuario.
    '-Nombre de seguridad, es decir, el identificador de usuario. Siempre va a ser 'admin' a partir de 2007
    '-Si el usuario está actualmente conectado a la base de datos.
    '-Si la conexión del usuario se terminó con normalidad.
'
'*************************************************************************************************************************************
'*************************************************************************************************************************************
'Copyright: Por favor, no cuesta nada mantener un enlace a mi web en el código.
'Incluso pudes dejar los formularios tal cual, con un enlace a mi web.
'Si vas a utilizar este código con fines lucrativos (es decir, te van a pagar por ello) contacta conmigo por favor.
'*************************************************************************************************************************************

Option Compare Database

Public Function Usuarios_Conectados(ByVal Fichero As String, ByVal Contraseña As String)

    On Error GoTo AlgoPasa

    Dim Conexion As New ADODB.Connection     'Para crear la conexión. Tengo que utilizar ADO, aunque no me guste
    Dim rsConexiones As New ADODB.Recordset  'Para la tabla que tendrá las conexiones
    Dim rsConectados As DAO.Recordset        'Para la tabla local que tendrá los usuarios conectados. Ya lo sabéis, no me gusta ADO, 😉
    Dim MiBD As DAO.Database                 'Muchos criticaréis esta forma, pero así utilizamos ADO y DAO de manera que los no iniciados aprendan

    Dim schemaID As String

    '**********************************************************************
    'En nuestro caso utilizamos JET_SCHEMA_USERROSTER -> {947bb102-5d43-11d1-bdbf-00c04fb92675}
    schemaID = "{947bb102-5d43-11d1-bdbf-00c04fb92675}"
    '**********************************************************************

    Conexion.Provider = CurrentProject.Connection.Provider 'Por si acaso asignamos el proveedor aunque se supone que será Microsoft ACE OLEDB 12.0

    If Len(Trim(Contraseña)) > 0 Then 'Si el usuario mete la contraseña. Si no tiene contraseña funciona bien aunque metas
            Conexion.Properties("Jet OLEDB:Database Password") = Contraseña
    End If
    Conexion.Open "Data Source=" & Fichero
    Set rsConexiones = Conexion.OpenSchema(schema:=adSchemaProviderSpecific, schemaID:=schemaID) ' Conexión sacada de la web de Microsoft

    Set MiBD = CurrentDb
    CurrentDb.Execute "DELETE * FROM CONEXIONES", dbFailOnError 'Vamos a borrar las conexiones anteriores
    Set rsConectados = MiBD.OpenRecordset("CONEXIONES")

    While rsConexiones.EOF = False

        rsConectados.AddNew
        rsConectados("HORA") = Now
        rsConectados("USUARIO") = Trim(rsConexiones!LOGIN_NAME)
        rsConectados("EQUIPO") = Trim(rsConexiones!COMPUTER_NAME)
        rsConectados("CONECTADO") = rsConexiones!CONNECTED
        rsConectados("ESTADO") = Trim(rsConexiones!SUSPECT_STATE)
        rsConectados.Update
        rsConexiones.MoveNext
    Wend
    rsConectados.Close
    Set rsConectados = Nothing
    rsConexiones.Close
    Set rsConexiones = Nothing

    Exit Function
AlgoPasa:

    MsgBox ("Error al comprobar las conexiones de usuarios. " & Err.Description), vbCritical, "Error al comprobar las conexiones"

End Function

Espero que os sirva.

The following two tabs change content below.
Arkaitz Arteaga
Llevo más de 10 años programando, sobre todo en Visual Basic y con bases de datos Access. Para mí, VBA y Access siguen siendo herramientas muy potentes. He desarrollado varios proyectos con PHP y MySql. Si sumo las webs que he tenido, probablemente pasaría de 100. Ahora prefiero dedicar todo mi esfuerzo a este blog (aunque sigo manteniendo unas cuantas...). Trabajo en la administración pública (si, soy funcionario), pero he trabajado en pequeñas empresas e incluso en una "grande" de las telecomunicaciones. Ultimamente estoy bastante metido en abrirme nuevos horizontes con C# y .NET. Renovarse o morir!

Deja un comentario