2017-02-18 3 views
0

Je voudrais savoir s'il est possible de verrouiller des tables de base de données à un utilisateur à la fois pour effectuer la terminologie ACID sur la base de données et autoriser une transaction complète à une heure dans la base de données Microsoft Access en utilisant VBA. Je cherche quelque chose comme le suivant dans le pseudocode:Verrouiller les tables de base de données à un utilisateur dans Microsoft Access VBA

  • Verrouiller toutes les tables (ou certaines tables).
  • Effectuez toutes les opérations SQL ou internes.
  • Effectuez la transaction et déverrouillez toutes les tables (ou certaines tables).

Mais, dans le cas d'une défaillance du client, par ex. l'application cliente est bloquée et l'utilisateur doit la fermer de force tandis que l'application cliente continue de traiter une transaction, elle annule les changements et ne fait jamais la transaction et déverrouille le verrou. Ce que je cherche est un verrou READ et WRITE, et le client qui essaye de verrouiller la base de données alors qu'il est déjà verrouillé, il devra attendre jusqu'à ce qu'il soit déverrouillé?

+0

Ceci est le début de ce que vous voulez http://stackoverflow.com/questions/5792169/opening-access-database-in-exclusive-mode#answer-5792773 –

Répondre

1

Enveloppez vos transactions dans une transaction de l'espace de travail:

Dim wks  As DAO.Workspace 
Dim dbs  As DAO.Database 

Set wks = DBEngine(0) 
Set dbs = wks.Databases(0) 

wks.BeginTrans 
    ' Do stuff using dbs and DAO. 
wks.CommitTrans 

Set dbs = Nothing 
Set wks = Nothing 

Si des erreurs sont potentiel, comprennent un gestionnaire d'erreur qui saute CommitTrans et appels:

wks.RollBack 
+0

Mais cela ne bloque pas non plus la lecture. J'ai déjà essayé ça !! – falhumai

+2

Vous auriez dû le mentionner dans votre question, en expliquant pourquoi vous pensez que cela ne résout pas votre problème. Je ne comprends toujours pas pourquoi les autres utilisateurs ne devraient pas avoir accès en lecture pendant l'exécution de la transaction. ACID (bien que Access ne s'y conforme pas entièrement) garantit qu'il n'y aura pas d'état incohérent dans la base de données: Soit la transaction est * terminée * avec succès, soit pas du tout. Il n'y a rien entre les deux. La lecture simultanée pendant la transaction d'un autre utilisateur est une fonctionnalité centrale garantie par ACID. – Leviathan

+1

@Leviathan a raison. Il n'y a aucun moyen de bloquer la lecture si l'utilisateur a accès au fichier. La lecture est le niveau d'accès le plus bas possible. L'accès ne peut être bloqué que si aucun utilisateur n'utilise la base de données; le premier utilisateur peut alors ouvrir le fichier exclusivement (vous pouvez l'appeler _single user mode_). Ensuite, aucun autre utilisateur ne peut ouvrir la base de données. Ceci, cependant, ne peut pas être fait dans VBA - il est contrôlé par la ligne de commande. – Gustav

0

En fait, j'ai trouvé un moyen de simuler l'accès mono-utilisateur pour la lecture et l'écriture à travers un type de verrou hacky composé. Ce qui suit décrirait comment je l'ai réalisé. Donc, j'ai fait une petite table en accès, disons Lock, et j'ai une colonne appelée SomeValue. Cette colonne doit être une clé primaire, et elle pourrait être de n'importe quelle valeur, donc je l'ai fait du type number, par exemple. Cette table stockera tous les verrous qui seront faits dedans, et les côtés qui essayent d'acquérir le verrou doivent s'accorder sur la valeur du verrou. Par exemple, deux clients vont essayer d'acquérir le verrou de la valeur 1, ils doivent donc demander le verrou 1 et libérer le verrou 1.

Tout d'abord, voici deux requêtes d'aide que j'ai fait pour régler et libérer le verrou, en faisant passer la valeur du verrou sur les côtés qui tentent d'acquérir:

requête SetLock:

INSERT INTO Lock (SomeValue) 
VALUES ([GetLockValue]); 

ReleaseLock requête:

DELETE * 
FROM Lock 
WHERE SomeValue=[GetLockValue]; 

Alors, voici la fonction TrySetLock (qui tenterait de régler le verrou du passé en valeur, et renvoie les résultats fixés, où 1 est un laissez-passer, et 0 est une fa il) et SetLock Sub (qui attendra jusqu'à ce que le verrou par le passé en valeur est vide pour l'acquérir - il utilise la méthode de verrouillage de rotation pour l'acquisition de verrouillage):

Public Function TrySetLock(LockValue As Integer) As Integer 
    Dim dbs As dao.Database 
    Dim qdf As dao.QueryDef 
    Set dbs = CurrentDb 
    Set qdf = dbs.QueryDefs("SetLock") 
    qdf.Parameters("GetLockValue").Value = LockValue 
    qdf.Execute 
    TrySetLock = qdf.RecordsAffected 
End Function 

Public Sub SetLock(LockValue As Integer) 
    Do While TrySetLock(LockValue) = 0 
    Loop 
End Sub 

Et voici la ReleaseLock Sub (qui libérerait le verrou par le passé en valeur - ce sous toujours réussir, même si une telle serrure existe):

Public Sub ReleaseLock(LockValue As Integer) 
    Dim dbs As dao.Database 
    Dim qdf As dao.QueryDef 
    Set dbs = CurrentDb 
    Set qdf = dbs.QueryDefs("ReleaseLock") 
    qdf.Parameters("GetLockValue").Value = LockValue 
    qdf.Execute 
End Sub 

Comme vous pouvez le voir ici, j'ai utilisé l'aide de la propriété clé primaire de SQL et Microsoft Accédez aux tables pour vous assurer que l'insertion (ou comme indiqué ici par le verrouillage) ne peut réussir que pour un côté ou un client à la fois, et ne réussira jamais pour l'autre côté à moins que le Le premier côté retire (ou libère) le verrou de la même valeur de la serrure des deux côtés. Cependant, cela poserait un problème de blocage de TOUS les clients utilisant un même verrou si un client ne réussissait pas à libérer le verrou (disons que le programme d'un client est gelé et qu'il a dû forcer le programme). Je voudrais savoir si les destructeurs pour les modules de classe seront appelés quand un programme est forcé d'être tué ou non? Si elle est appelée, alors je pense que ce problème peut être résolu en faisant une classe de verrou avec une certaine valeur, et le destutor de cette classe libère le verrou, et ne pas avoir à faire attendre d'autres clients pour ce verrou certain.