Access: Probleme beim Betrieb mit mehr als einem Benutzer

Liebe/-r Experte/-in,
Guten Tag,
ich habe Access 2007 unter Windows 7 im Einsatz. Die Tabellen sind von den Formularen in einer separaten Datenbank getrennt. Die Anwendung entwickle ich für die Seniorenhilfe in Langen (das ist tolle gemeinnützige Initiative, der ich natürlich kostenlos zuarbeite)

Im Einzelbetrieb läuft die Anwendung. Sobald ich aber mit 2 Benutzern gleichzeitig arbeite, kommt es manchmal zu Konflikten. Damit meine ich auch (aber nicht nur) dass ein Datensatz von 2 Benutzern gleichzeitig geändert werden soll und sich Access dann folgerichtig meldet.

Ich glaube 3 Probleme zu haben, die alle mit einem (fast) zeitgleichen Zugriff auf gleiche Tabellen oder Datensätze zusammenhängen. Ich bekomme falsche Anzeigen von der Anwendung in den Formularen oder Warnmeldungen von Access. Wenn ich die gleiche Aktion nicht fast zeitgleich oder bei falscher Anzeige nach einer Minute wiederhole, dann stimmt wieder alles.

Problem 1:
Offensichtlich kann der VBA-Befehl DoCmd.RunSQL „Delete * from AuswahlTabMNr;“ nicht ausgeführt werden, weil ein anderer Benutzer diese Aktion gerade für die Tabelle ausführt. In der weiteren VBA-Befehlsfolge wird die Tabelle (die jetzt gelöscht bzw. leer sein sollte) mit einer passenden Auswahl gefüllt und Im Formular wird später gezählt, wie viel Einträge die Tabelle AuswahlTabMNr aufgrund der passenden Auswahl hat.

Der Teil des VBA-Codes:
DoCmd.SetWarnings False 'Warnmeldungen ausschalten
DoCmd.RunSQL „Delete * from AuswahlTabMNr;“
DoCmd.RunSQL „Delete * from BankenTab;“
Me.Refresh
AnzahlAuswahlTabMNr = „“
Im Fehlerfall werden die Einträge für die Tabelle AuswahlTabMNr nicht gelöscht und dann aber trotzdem gefüllt – die gezählten Einträge sind dann also doppelt so hoch.
Meine Frage: wie kann ich erreichen, dass die Tabellensätze trotzdem gelöscht werden? Soll ich die Tabelle aus der getrennten Datenbank trennen und zu den Formularen packen, damit jeder Benutzer seine eigene Tabelle aufbaut? Ich zögere nämlich, die Tabelle ganz zu sperren, da diese auch noch in anderen Formularen gebraucht wird.

Problem 2:
Aufgrund einer Vorlage (das ist ein normales Formular) kann ich per Button auslösen, dass aufgrund dieser Vorlage in einer anderen Tabelle der höchste Ordnungsbegriff gesucht und dann ein neuer Satz in dieser anderen Tabelle mit einem Ordnungsbegriff +1 angelegt wird. Der Ordnungsbegriff ist gleichzeitig der Index.
Auch hier führt der fast zeitgleiche Zugriff dazu, dass beide Benutzer den gleichen höchsten Ordnungsbegriff genannt bekommen. Beide wollen danach einen neuen Satz in die Tabelle speichern – es kommt zwangsläufig zu einem (verbotenen) gleichen Indexeintrag, der natürlich von Access per Fehlermeldung verhindert wird. Aber der unbedarfte Benutzer ist verunsichert.
Meine Frage: wie kann ich das verhindern. Mein (umständlicher??) Lösungsansatz wäre, sich den höchsten Ordnungsbegriff geben zu lassen und vor dem endgültigen Schreiben des neuen Satzes nochmal abzufragen, ob es diesen Index inzwischen gibt – und dem Benutzer dann die Aktion per Fehlermeldung von mir abzubrechen.

Problem 3a:
Benutzer A und B haben das gleiche Mitglied in Bearbeitung. Jeder will den Datensatz ändern. Ich habe die Datensätze nicht gesperrt. Access merkt den Konflikt und gibt dem Benutzer B eine entsprechende Fehlermeldung. Benutzer B kann dann die Änderung auf der von Access angezeigten Fehlermeldung durch Auswahl des entsprechenden Buttons verwerfen. Dabei kommt es aber zu einer weiteren Fehlermeldung, die der Benutzer ebenfalls quittieren kann. Soweit so gut.
Meine Frage: kann ich diese Situation vermeiden? Sätze möchte ich dabei ungern sperren. Kann ich die Fehlermeldung abfangen?

Problem 3b:
Wenn es schon eine Fehlermeldung gibt (sie kann auch anderen Gründen auftreten), dann gehen der Anwendung globale Variablen verloren. Das ist unschön und führt anschließend zu einer Division durch Null – also zu einer weiteren Fehlermeldung. Viel unschöner ist aber, dass der Benutzer nicht zu dem Formular zurückkehren kann, das den Fehler ausgelöst hat. (Ich zeige alle geöffneten Formulare als Registerreiter an). Letztlich bleibt dem Anwender oft nur, das Register mit der rechten Maustaste anzuklicken und dann zu schließen. Dazu sind die Benutzer (alles ältere Leute!) häufig nicht qualifiziert genug. Es genügt da schon die kleinste Störung/Abweichung vom gewohnten Ablauf, um sofortige Konfusion auszulösen.
Es ist also meine Aufgabe, solche Störungen abzufangen. Vielleicht gibt es aber irgendwo eine Einstellung, dass das fehlerauslösende Formular wieder angesprochen (aktiviert) werden kann?

Auch wenn das Vorstehende professionell klingt – ich bin trotzdem kein geübter Accessanwender. Ich kann nur von Excel her auch VBA. Darum bitte ich die erbetene Hilfen/Lösungen/Erklärungen meinem niederen Niveau anzupassen. Danke!!

Hallo

ich versuche gerne zu helfen, sind zwar gerade etwas viele Fragen :wink:

Also, zu Problem 1:
Ich habe dasselbe Problem schon mehrfach gehabt. Insbesondere bei Aufbereitung von Selektionen … du hast mit dem Vorschlag mit der Übernahme der Tabelle in die „Software-DB“ die Lösung bereits gefunden. Meiner Meinung nach gehört die in diesem Beispiel sowieso da hin :wink:

zu Problem 2:
Du musst im gleichen Moment wie du den neuen Record anlegst, diesen auch gleich speichern. Damit ist sichergestellt, dass bevor alle Daten eingegeben sind, ein weiterer User die bereits nächst höhere Nummer heranzieht.

Sollte das Problem der leeren Felder noch sein, dann kannst du diese auf 2 Varianten verhindern:

  1. Du machst beim Verlassen des Formulars die Tests manuell und verbietest das Verlassen des Formulares ohne das Ausfüllen aller Pflichtfelder…
  2. Du löschst mit Hilfe einer Abfrage solche leeren Datensätze einfach wieder raus. Du wirst im Hintergrund dann Lücken in den Nummern haben, was meist „Wurst“ ist

Also: Datensatz anlegen und gleich speichern, dann füllt der User seine Daten ab und speichert erneut. In dieser Zeit bekommt aber ein weiterer User bereits die nächst höhere Nummer und nicht mehr dieselbe!

Problem 3a:
Ich würde den Datensatz für eine Änderung komplett sperren. Diese Standardeinstellung kannst du für die Datenbank wie folgt einstellen: Extras - Optionen, dann Klick auf Registerkarte „Weitere“ …
Darin sind diverse mögliche Einstellungen verfügbar für die Sperrung eines Records, während dieser gerade in Bearbeitung ist.

Problem 3b:
Es ist tatsächlich ein Problem, dass bei Eintreten eines Fehlers, sämtliche Globale Variablen gelöscht werden. Es gibt aber eine Lösung für dieses Problem!

TempVars heisst das Zauberwort!

Ich habe ein Mailabonnement von SmartTools, was ich sehr empfehlen kann, hin und wieder kommen brauchbare Tipps!

schaue mal nach z.B. hier:
http://www.access-entwicklerbuch.de/2007/index.php?p…

Hoffe, konnte dir evtl. etwas weiterhelfen.

Viel Spass und Gruss
Dani

Problem 1:
Offensichtlich kann der VBA-Befehl DoCmd.RunSQL „Delete *
from AuswahlTabMNr;“ nicht ausgeführt werden, weil ein anderer
Benutzer diese Aktion gerade für die Tabelle ausführt.

Access sperrt leider immer ganze Gruppen von Datensätzen, nicht nur den, den man gerade bearbeiten möchte. Wurde wohl von Microsoft so gemacht weil es etwas performanter und leichter auszuprogrammieren ist. Macht aber in der Praxis eben entsprechend ärger.

Statt „Docmd.RunSQL“ verwende überall „Currentdb.Execute“ - dann erspart Du dir alle mühsamen Standard-Access-Meldungen wenn mal was nicht klappt. Ich weiß nicht wie genau deine Datenbank aufgebaut ist. Aber wenn Du jeden Benutzer praktisch als Mandanten behandelst, kannst Du innerhalb einer einzigen Tabelle für jeden einzelnen Benutzer Datensätze gespeichert haben und gleichzeitige Zugriffe minimieren (nicht verhindern weil ja Access leider immer ganze Blöcke sperrt, da können dann auch solche anderer Mandaten dabei sein). Führ also einfach z.b. die Benutzerkennung als Spalte mit und leg - wofür Du das auch immer brauchst - für jeden einzelnen Benutzer eigene Datensätze in der Tabelle an von dem Du jedem Benutzer nur seine eigenen zeigst.

Problem 2:
Aufgrund einer Vorlage (das ist ein normales Formular) kann
ich per Button auslösen, dass aufgrund dieser Vorlage in einer
anderen Tabelle der höchste Ordnungsbegriff gesucht und dann
ein neuer Satz in dieser anderen Tabelle mit einem
Ordnungsbegriff +1 angelegt wird. Der Ordnungsbegriff ist
gleichzeitig der Index.
Auch hier führt der fast zeitgleiche Zugriff dazu, dass beide
Benutzer den gleichen höchsten Ordnungsbegriff genannt
bekommen. Beide wollen danach einen neuen Satz in die Tabelle
speichern – es kommt zwangsläufig zu einem (verbotenen)
gleichen Indexeintrag, der natürlich von Access per
Fehlermeldung verhindert wird. Aber der unbedarfte Benutzer
ist verunsichert.
Meine Frage: wie kann ich das verhindern. Mein
(umständlicher??) Lösungsansatz wäre, sich den höchsten
Ordnungsbegriff geben zu lassen und vor dem endgültigen
Schreiben des neuen Satzes nochmal abzufragen, ob es diesen
Index inzwischen gibt – und dem Benutzer dann die Aktion per
Fehlermeldung von mir abzubrechen.

Hier hast Du Dir die Antwort bereits selbst gegegeben. Bei gleichzeitigen Neuanlagen kann es in jedem System zu doppelten Einträgen kommen weil man ja nie weiß, was die anderen Benutzer grade so im Programm machen. Eine nochmalige Kontrolle ob es zwischenzeitlich keine Fremde Anlage gleichen Inhalts gab wird also wirklich die beste Lösung sein in diesem Fall.

Problem 3a:
Benutzer A und B haben das gleiche Mitglied in Bearbeitung.
Jeder will den Datensatz ändern. Ich habe die Datensätze nicht
gesperrt. Access merkt den Konflikt und gibt dem Benutzer B
eine entsprechende Fehlermeldung. Benutzer B kann dann die
Änderung auf der von Access angezeigten Fehlermeldung durch
Auswahl des entsprechenden Buttons verwerfen. Dabei kommt es
aber zu einer weiteren Fehlermeldung, die der Benutzer
ebenfalls quittieren kann. Soweit so gut.
Meine Frage: kann ich diese Situation vermeiden? Sätze möchte
ich dabei ungern sperren. Kann ich die Fehlermeldung abfangen?

Sperren sind ja dazu da um solche Konflikte zu vermeiden. Nutze sie auch! (Stell bei der Datenbank die Sperrung des bearbeiteten Datensatz ein - der aber leider, muss das nochmal erwähnen, trotzdem blockweise erfolgt). Ist aber besser, als die ganze Datenbank exklusiv für einen Benutzer zu sperren.

Problem 3b:
Wenn es schon eine Fehlermeldung gibt (sie kann auch anderen
Gründen auftreten), dann gehen der Anwendung globale Variablen
verloren. Das ist unschön und führt anschließend zu einer
Division durch Null – also zu einer weiteren Fehlermeldung.

Eine Division durch Null darf eigentlich niemals passieren weil man die - bei gutem Programmierstil - immer abfrägt. Aber ich weiß natürlich was Du meinst. In diesem Fall führst Du einfach eine weitere globale Variable ein und nennst sie z.b. „allesInitialisiert“. Die kannst Du z.b. vom Typ Boolean anlegen und ihr den Wert „True“ geben sobald alle relevanten anderen globalen Variablen ihre gültigen Werte von Dir erhalten haben. Du fragst dann einfach vor jeder Verarbeitung ab „if allesInitialisiert = TRUE then“. Verliert Access - aus welchem Grunde auch immer - nach einem Fehler die Initialisierung, dann verliert es diese auch von Deiner Spezialvariable. Die ist dann eben nicht mehr „TRUE“ und da du überall danach abfragst können auch keine weiteren Fehler mehr passieren. Du kannst in diesem Fall sogar automatisch das betroffene Formular - oder sogar das ganze Programm - neu laden lassen damit alles wieder initialisiert und sauber ist und der Benutzer keinen Handlungsbedarf hat. Ich hoffe ich konnte Dir damit zumindest ein klein Wenig helfen…

Hallo „becker“,

nachdem ich mal das ganze Problem von Dir gelesen habe, würde ich pauschal mal sagen, daß Du die angehängte Datenbank ändern solltest. D. h. nicht eine Access-DB-Datei im Hintergrund für die Datenspeicherung sondern die Express-Edition vom SQL2005-Server oder SQL2008-Server. Ein vollwertiger SQL-Server wäre wohl ein bißchen zu überdimensioniert. So viel ich weiß wird die Express-Editon sogar mit Access 2007 ausgeliefert.
Als sog. Front-End kannst Du aber weiter Access benutzen, in dem Du dann die Formulare und Reports bearbeitest und zur Verfügung stellst. Ich selber arbeite mit Access 2003 und einem SQL2005 Server für die Datenhaltung.

Der SQL-Server ist für einen Mulit-User-Betrieb ausgelegt, Access eigentlich für einen Einzelbenutzer-Betrieb.

Der Nachteil an der ganzen Sache ist aber, daß der SQL-Server wesentlich komplexer ist als Access und daher eine längere Einarbeitung mit sich zieht.

Jetzt mal etwas detaillierte zu den Problemen:

Problem 1
Wenn ein Benutzer Daten ändert, wir die Tabelle für weitere Änderungen gesperrt. Deshalb kommt es zu der Fehlermeldung beim Löschen.
Beim SQL-Server hättest Du die Möglichkeit, sog. Sperrvermerke bei den Abfragen mitzugeben. Das hilft Dir bei Access aber nicht weiter.
Entweder legst Du vor dem Öffnen des Formulars für jeden Benutzer eine temporäre Tabelle an und kopierst die benötigten Daten hinein oder Du gibst jeden User eine Art ID beim öffnen des Formulars, die dann in der Tabelle mit geführt wird. Dann greift der user nur auf die IDs zu. Allerdings hast Du dann in der Tabelle doppelte Datensätze, die Du aber üder die Abfrage der User_ID begrenzst.

Problem 2
Hier könnte eine weitere Tabelle helfen, in der Du die Indizes selber verwaltest. Die Tabelle könnte heißen und aus den Spalten und bestehen.
Vor dem Einfügen neuer Datensätze wird der aktuelle Index gelesen, um 1 erhöht und wieder weggeschrieben.
Hierzu solltes Du Dir auch mal die Hilfe zu OpenRecordset(DAO) ansehen. Hier gibt es ein paar Parameter, mit denen Du den Zugriff steuern kannst.

Problem 3:
Um Satzsperren wirst Du bei einem Mehrbenutzerumgebung nicht drum herum kommen.
Fehler fängst Du (zumindest bei Access2003) mit dem Befehl ab. Am besten mal die Hilfe dazu aufrufen.

Die Fehlerbehandlung wird Dir auch bei Deinem Problem 3b weiterhelfen, da Du mit dieser die Anwendung steuren kannst, ohne das Variablen gelöscht werden, weil Access auf einen Fehler läuft.

Ich hoffe, daß ich ein bißche helfen konnte.
Wenn es detaillierter werden soll, dann bräuchte ich mal die beiden Dateien, um mir das näher anzusehen.

Gruß
Ingo

Hallo Dani,

vielen Dank für die prompte Antwort. Deine Antwort war verständlich und ich kann und werde deinem Rat folgen.

Freundliche Grüße
Harald

Hallo Andi,

vielen Dank für die prompte Antwort. Deine Antwort war verständlich und ich kann und werde deinem Rat folgen.

Freundliche Grüße
Harald

Hallo Ingo,

vielen Dank für die prompte Antwort. Deine Antwort war verständlich und ich kann und werde deinem Rat folgen.

Freundliche Grüße
Harald

ich würde auf jeden Fall nicht mit Docmd.RunSQL arbeiten, sondern mit der Execute-Methode und dann die Fehler entsprechend abfangen.

Es kann auch erforderlich sein, die Aktionen in Transaktionen zu kapseln. (Siehe Hilfe: BeginTrans, CommitTrans usw.

Gruß
Reinhard Kraasch

Sorry hatte ein paar Probleme,

ist die Anfrage gelöst?

Sorry hatte ein paar Probleme,

ist die Anfrage gelöst?

Danke, Alois. Mein Problem ist gelöst.