sschultewolter
Goto Top

Access Frontend mit MariaDB - Speicherkonflikt

Guten Tag,

ich habe ein Access Frontend, welches auf einen MariaDB Server im Netzwerk zugreift. Dort habe ich Kundendaten (Projekt-Nr, Kundenanschrift etc. hinterlegt).
screenshot 2023-07-17 191151

Mit der Datenbank arbeiten im Betrieb inzwischen ca. 10 Personen. Wobei hier zu 95% die Mitarbeiter nur auf die Daten zugreifen und nicht ändern.

Die Datenbank wird beim Start immer mit Schreibschutz geöffnet. Sobald der Schreibschutz in Access aufgehoben wurde, läuft ein Timer, nach dem der Schreibschutz wieder aktiv ist. Bei nicht gespeicherten Datensätze habe ich dann noch die Abfrage drin, ob diese gespeichert werden sollen.

Jedoch erhalte ich immer wieder folgenden Fehler
screenshot 2023-07-17 191736

Wie kann ich einen solchen Fehler unterbinden. Habe im Netz bereits nach dem Problem gesucht. Teils wird etwas von einem Timestamp gesprochen, diesen habe ich auf in MariaDB hinterlegt. Was danach aber damit genau gemacht werden soll, wurde nicht erklärt. So hat dieser keine Funktion.

screenshot 2023-07-17 192112

Aktuell wird der Recordsettyp Dynaset verwendet. Ich hoffe das reicht euch schon etwas aus, wenn nicht, einfach fragen. Hier ist auch noch Teil des Quellcodes. Habe bewusst einige Subs nicht mit gepostet, da es dann etwas zu lang wird. Kann diese aber ggf. als Anhang noch nachreichen. Ist noch nicht sauber dokumentiert (das wollte ich im Anschluss nach dieser Problemlösung machen mit einem externen Editor, da mir Access alles unsauber einrückt).


Option Compare Database
Option Explicit

' ********************************************************************************  
' ** Konstanten  
' ********************************************************************************  
Const strRoot = "\\192.168.99.2\kunden\"  
Const InitCtSchreibschutz = 30      'Zeit, wie lange Schreibschutz aufgehoben wird  


' ********************************************************************************  
' ** Globale Variablen  
' ********************************************************************************  
Public blnErweiterteAnsicht As Boolean
Public ctLeseDatensaetze As Integer
Public ctSchreibschutz As Integer





' ********************************************************************************  
' ** Ereignisse Formular  
' ********************************************************************************  
Private Sub Form_Load()
    txt_filter_beliebig = ""  
    filter_beliebig
    SetzeSchreibschutz
    LeseDatensaetzeMax
End Sub


Private Sub SetzeSchreibschutz()
    status_gesperrt.BackColor = RGB(255, 0, 0)
    btn_sperre.BackStyle = 0
    status_gesperrt.Caption = 0

    btn_Datensatz_speichern.Enabled = False
    btn_datensatz_verwerfen.Enabled = False
    btn_Datensatz_hinzufuegen.Enabled = False
    
    If Me.Dirty = True Then
        If MsgBox("Der Datensatz wurde noch nicht gespeichert. Speichern?", vbOKCancel, "Speichern") = vbOK Then  
            DoCmd.RunCommand acCmdSaveRecord
            MyDebug ("Datensatz " & txt_bhkw_projekt_nr & " wurde gespeichert")  
        Else
            Me.Undo
            MyDebug ("Datensatz " & txt_bhkw_projekt_nr & " wurde verworfen")  
        End If
    End If
    
    Dim ctl As Control
    For Each ctl In Me.Section(0).Controls
    If (ctl.ControlType = acTextBox Or ctl.ControlType = acComboBox Or ctl.ControlType = acCheckBox) Then
        ctl.Locked = True
    End If
    Next ctl
End Sub


Private Sub LoescheSchreibschutz()
    status_gesperrt.BackColor = RGB(0, 255, 0)
     btn_sperre.BackStyle = 1

    btn_Datensatz_hinzufuegen.Enabled = True
      
    Dim ctl As Control
    For Each ctl In Me.Section(0).Controls
    If (ctl.ControlType = acTextBox Or ctl.ControlType = acComboBox Or ctl.ControlType = acCheckBox) Then
        ctl.Locked = False
    End If
    Next ctl
End Sub



' Navibuttons  
Private Sub btn_datensatz_verwerfen_Click()
MyDebug ("btn_datensatz_verwerfen_Click")  
    
   Me.Undo
   
   btn_datensatz_verwerfen.Enabled = False
   btn_Datensatz_speichern.Enabled = False
End Sub

Private Sub btn_Datensatz_speichern_Click()
  MyDebug ("btn_Datensatz_speichern_Click")  
'On Error Resume Next  
    Me.Dirty = False
   ' DoCmd.RunCommand acCmdSaveRecord  

    btn_Datensatz_speichern.Enabled = False
    btn_datensatz_verwerfen.Enabled = False
End Sub

Private Sub btn_Datensatz_hinzufuegen_Click()
  MyDebug ("btn_Datensatz_hinzufuegen_Click")  

    DoCmd.GoToRecord , , acNewRec
End Sub

Content-ID: 7879836126

Url: https://administrator.de/contentid/7879836126

Ausgedruckt am: 26.11.2024 um 10:11 Uhr

MirkoKR
MirkoKR 17.07.2023 um 19:45:07 Uhr
Goto Top
Zitat von @sschultewolter:


Die Datenbank wird beim Start immer mit Schreibschutz geöffnet. Sobald der Schreibschutz in Access aufgehoben wurde, läuft ein Timer, nach dem der Schreibschutz wieder aktiv ist. Bei nicht gespeicherten Datensätze habe ich dann noch die Abfrage drin, ob diese gespeichert werden sollen.

Jedoch erhalte ich immer wieder folgenden Fehler

Es wird noch nicht ganz deutlich, ob du nur innerhalb des Acces-Frontend die Schreibsperre aufhebst/setzt oder du das auch der Datenbank mitteilst?

Üblich wäre im Datensatz oder einer Sperrtabelle, ein Flag zu setzen, das im Access-Frontend vor der Aufhebung der Sperre geprüft, ob eine Sperre gesetzt ist, diese ggf. gesetzt/gelöscht wird.
sschultewolter
sschultewolter 17.07.2023 um 19:54:04 Uhr
Goto Top
Hallo MirkoKR,

danke schon einmal vorweg für deine Antwort.

Aktuell wird nur innerhalb des Frontends die Eingabefelder etc. gesperrt. Bin mir noch nicht sicher, wie ich die Sperre über ein Flag in der Datenbank (MariaDB) realisieren kann.

Weil...
... Mitarbeiter startet eine Änderung, und Access würde abstürzen etc, also der Datensatz würde nicht wieder freigegeben werden.

Um deinen Ansatz zu verstehen, würde das wie folgt in etwa ablaufen

1. Schreibschutz in Access aktiv
2. Schreibschutz in Access aufheben, wenn das Flag = 0 (nicht aktiv) ist
3. Flag = 1
4. Speichern und Flag = 0 setzen
MadMax
MadMax 17.07.2023 um 20:29:55 Uhr
Goto Top
Hallo sschultewolter,

normalerweise kannst Du beim Öffnen Deines Recordset einen LockType angeben. So wie ich Deine Datensatzbearbeitung verstanden habe, müßtest Du dort eine pessimistische Sperre angeben. Wenn der Benutzer den Datensatz bearbeiten will, liest Du den Datensatz und sperrst ihn dabei. Wird der Datensatz gespeichert, wird die Sperre beendet. Bricht die Datenbankverbindung durch irgendwas ab, z.B. durch einen Rechnerabsturz, wird die Sperre automatisch aufgehoben.

Gruß, Mad Max
MirkoKR
MirkoKR 17.07.2023 aktualisiert um 21:18:31 Uhr
Goto Top
Weil...
... Mitarbeiter startet eine Änderung, und Access würde abstürzen etc, also der Datensatz würde nicht wieder freigegeben werden.

Um deinen Ansatz zu verstehen, würde das wie folgt in etwa ablaufen

1. Schreibschutz in Access aktiv
2. Schreibschutz in Access aufheben, wenn das Flag = 0 (nicht aktiv) ist
3. Flag = 1
4. Speichern und Flag = 0 setzen

Naja:
bLocked: True/False
LockTime: TimeStamp
optional: LockedBy: UserName

Das entweder pro Datensatz oder mit DatensatzID in einer tLocked - Tabelle.

Damit kannst du beim Starten des Frontend prüfen, ob der gewünschte Datensatz gesperrt ist und ggf., wenn LockedTime > 30 Minuten her ist den Datensatz zwangsentsperren - dann sollte aber auch das Frontend des ursprünglichen Users auf diese Zwangsentsperrung mit einem Schreibschutz bzw. Datensatz verwerfen und optional einem Popup-Hinweis rwagieren ...

Was das Beste ist, müsst ihr wissen ...

Nachtrag: Alternativ, und eleganter ist der Einsatz von StoredProcedures, wo die Sperrlogik Datenbankseitig verwaltet wird ...

Nachtrag2: achja: und natürlich Event-getriggerte Abläufe, also z.B. nach Zeit, nach/vor dem Einfügen oder Update, etc ...
sschultewolter
sschultewolter 17.07.2023 um 21:37:21 Uhr
Goto Top
Zitat von @MadMax:

Hallo sschultewolter,

normalerweise kannst Du beim Öffnen Deines Recordset einen LockType angeben. So wie ich Deine Datensatzbearbeitung verstanden habe, müßtest Du dort eine pessimistische Sperre angeben. Wenn der Benutzer den Datensatz bearbeiten will, liest Du den Datensatz und sperrst ihn dabei. Wird der Datensatz gespeichert, wird die Sperre beendet. Bricht die Datenbankverbindung durch irgendwas ab, z.B. durch einen Rechnerabsturz, wird die Sperre automatisch aufgehoben.

Gruß, Mad Max

Hört sich soweit nicht verkehrt an. Habe aktuell aber noch nichts hilfreiches dazu gefunden. Soweit ich rausbekommen habe, betrifft "Datensatz sperren" unter Formulareigentschaften nur die MDB.

Werde das ganze erst einmal wie folgt versuchen

  • neue Tabelle (lock) mit ID, User, Timestamp
  • Datenbank lesend öffnen
  • Bearbeiten > Fragt ob, ein Zeitstempel innerhalb einer Zeitinterval liegt
  • Wenn noch innerhalb der Zeitinterval, soll der Benutzer mit Uhrzeit ausgegeben werden
  • Ist die Zeitinterval abgelaufen, setze diese beim Bearbeiten neu
  • Wurde Datensatz gespeichert, wird Timestamp gelöscht
MirkoKR
MirkoKR 17.07.2023 um 21:56:18 Uhr
Goto Top
.
Werde das ganze erst einmal wie folgt versuchen

  • neue Tabelle (lock) mit ID, User, Timestamp

Klingt viepversprechend, evtl. zusätzlicher Nebeneffekt: eine Protokolldatei, wer welchen Datensatz wann geändert hat ... face-wink
TommyPinballWizzard
TommyPinballWizzard 18.07.2023 um 08:25:17 Uhr
Goto Top
Hallo,

ich kenne das von Access wenn 2 User auf den gleichen Datensatz sind.

Gruß
sschultewolter
sschultewolter 18.07.2023 um 10:44:05 Uhr
Goto Top
Hallo,

habe aktuell mir die Spalte für Timestamp angelegt.

CREATE TABLE `kunden_2022` (
  `timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Funktioniert soweit auch. Bei Änderungen in Access oder über phpMyadmin wird die Zeit dann aktualisiert.


Bearbeite ich nun einen Eintrag so hat phpMyAdmin immer Vorang, heißt auch wenn ich in Access zwischenzeitlich etwas ändere, übernimmt phpMyAdmin das nicht und speichert, so wie es mir aktuell im Editor angezeigt wird ab. Passt für mich erst einmal.

Ändere ich in phpMyAdmin etwas, wenn ich Access ebenfalls darauf bin, und speichere, dann bekomme ich diesen Konflikt.


Wie sieht die Logik in Access dafür genau aus, ggf. auch nen Code Snippet. Habe keine Seite gefunden, bei der das auch einmal näher erklärt wird.

Ich müsste im Prinzip den aktuellen Timestamp in Access bekommen, der gerade in der Datenbank ist (nicht im Frontend)
MirkoKR
MirkoKR 18.07.2023 um 11:01:35 Uhr
Goto Top
Da du ja in Access die Tabellen/Abfragen direkt verknüpfst, hast du auch eine eigene Zugriffsverwaltung.

Ich würde mal behaupten, das Access für euren Fall das falsche Frontend ist.

Du scheinst ja auch recht firm/motiviert zu sein, sodass ich dir empfehlen möchte, dein Frontend in PHP, C#, etc. aufzubauen. zumal du dort auch besser mit StoredProcedures, etc. arbeiten kannst ...

Ein Blick auf PowerBI ist aber auch nicht verkehrt ...