Datensatzsperrung unter H2 Database

Status
Nicht offen für weitere Antworten.

Alex_winf01

Top Contributor
Hallo liebe Forengemeinde,

im folgenden Beitrag wurde mir ja schon geholfen:
Client-Server

Kennt jemand noch eine andere Möglichkeit einen Datensatz in der H2-Datensatz sperren zu lassen, als eine Spalte "inBearbeitung" einzufügen und wenn ein bestimmter DS aufgerufen wird, dieses Feld auf "true" zu setzen? Bei Update und Delete wird diese Spalte abgefragt, ob diese true/false ist. Bei True kann kein Update/Delete durchgeführt werden.
 

ms

Top Contributor
Öhm ... in dem verlinkten Thread hab ich Optimistic Locking und Transaktionen schon beschrieben.
Was gefällt dir daran nicht?
Die Variante mit der in-Bearbeitung-Spalte ist eine Krücke und wird nicht wirklich funktionieren.

ms
 

Alex_winf01

Top Contributor
@ ms

Ich habe mal kurz gelesen. Also mit Hibernate wird ja "nur" verglichen, ist der DS wirklich noch der, der er war. Wenn ja, wird er geändert. Wenn nein gibt es eine Fehlermeldung. D. h. es kann sehr wohl sein, dass ein anderer den entsprechenden DS ändert. Das soll aber gar nicht erst so weit kommen.

Was anderes mache ich mit der Spalte inBearbeitung auch nicht. Wenn diese Spalte true ist, kann ein anderer Anwender gar nicht erst updaten oder löschen. Er bekommt die Fehlermeldung, dass der entsprechende DS gerade in der Bearbeitung ist. OK es ist eine Krücke, aber warum sollte es nicht funktionieren? Welche Probleme können auftreten?
 

ms

Top Contributor
Wenn du es so machst wie du sagst, dann musst du doch, bevor du den Datensatz sperrst (also die Spalte InBearbeitung auf TRUE setzt) den Datensatz abfragen ob er nicht gerade durch einen anderen User gesperrt ist. Das sind also zwei Statements die in einer Transaktion laufen sollten. Ansonsten kann es Überschneidungen geben wenn zwei Benutzer gleichzeitig abfragen ob der Datensatz gerade gesperrt ist. Beide bekommen ein FALSE zurück und beide führen dann das Update-Statement aus. Beide Benutzer sind also der Meinung, dass die Daten exklusiv ihnen zur Bearbeitung gehört was natürlich nicht stimmt.
Gut, du könntest natürlich so wie schon erwähnt in dem Update-Statement eine Where-Bedingung anhängen, die auf die Spalte InBearbeitung auf FALSE geht. Dann hast du aber erst wieder eine Art Optimistic Locking eingebaut.
Von gejointen Daten wollen wir erst gar nicht sprechen.

ms
 

Alex_winf01

Top Contributor
Dann hast du aber erst wieder eine Art Optimistic Locking eingebaut.

Du meinst also, ich bilde das Optimistic Locking nach? Zumindestens im weitesten Sinne. Hintergrund, warum ich das so mache:

Vom Kunden ist es gewollt, dass der DS nicht von einem Anwender bearbeitet werden kann, wenn dieser gerade von einem anderen Anwender bearbeitet wird. Also das Gegenteil, was Hibernate macht. Beispiel: Anwender A öffnet DS A zur Bearbeitung. Anwender B öffnet auch DS A. Anwender A soll den DS bearbeiten könne, Anwender B jedoch nicht. Wenn ich Hibernate richtig verstehe, kann Anwender B sehr wohl den DS A bearbeiten. Anwender A bekommt dann die Rückmeldung, dass der DS geändert wurde und aus dem Grunde nicht gespeichert werden kann.
 

FenchelT

Bekanntes Mitglied
Hallo Alex,

Du solltest Dich nochmal naeher mit datenbankseitigen Transaktionen beschaeftigen.
Denn mitunter ist es auch Aufgabe der Transaktionen, solche Dinge zu vermeiden. Dafuer brauchst Du eigentlich gar keine eigene Locking Methode einfallen lassen,
das kann die DB eigentlich besser und von alleine, sofern die von Dir eingesetzte MySQL Version Transaktionen unterstuetzt.

Gruesse
 

Alex_winf01

Top Contributor
@ FenchelT

Die Varianta mit Hibernate wird vom Kunden nicht gewollt und H2 unterstützt nur Database Locking und nicht für den einzelnen Datensatz.

@ ms

war das so gemeint, wie ich geschrieben habe?
 
G

Guest

Gast
ms hat gesagt.:
Anonymous hat gesagt.:
SELECT ... FOR UPDATE macht ein Row-Lock.
It is also possible to lock a table exclusively without modifying data, using the statement SELECT ... FOR UPDATE.
Quelle: http://www.h2database.com/h2.pdf (Seite 30, Locking, Lock-Timeout, Deadlocks)
Also kein Row-Lock.

ms
Ok, wo wir schon unterstreichen... ;)
It is also possible to lock a table exclusively without modifying data, using the statement SELECT ... FOR UPDATE.
Soll heissen, dass es ebenfalls möglich ist eine ganze Tabelle zu sperren. Dies schliesst einen Write-Lock auf Datensatzebene nicht aus.
So verstehe ich es zumindest. Einfach ausprobieren. Aus zwei Connections heraus (autocommit off) ein SELECT...FOR UPDATE auf gleiche
Datensätze ausführen.
Ich habe hier keine H2-DB auf dem PC, das sollte aber mit zwei Web-Console Fenstern schnell zu testen sein.
 
G

Guest

Gast
Alex_winf01 hat gesagt.:
@ ms

Du meinst also, ich bilde das Optimistic Locking nach? Zumindestens im weitesten Sinne.

Leider wurde meine Frage noch nicht beantwortet (vielleicht übersehen?)
Hibernate (bzw. JPA) hat es bereits integriert. Wenn du es von Hand für jede Tabelle machst, wird es ziemlich umständlich.
Es hängt aber davon ab, was dein Anwendungsszenario ist. "Concurrent updates" zu erkennen oder zu unterbinden. Für's Erste
ist die Lösung OK, beim Zweiten wird es viel komplizierter. In beiden Fällen hast du aber ein Read-Before-Update drin.
 
M

maki

Gast
Dann zitieren wir mal alles und reissen nix aus dem Kontext:
Locking, Lock-Timeout, Deadlocks

The database uses table level locks to give each connection a consistent state of the data. There are two kinds of locks: read locks (shared locks) and write locks (exclusive locks). If a connection wants to reads from a table, and there is no write lock on the table, then a read lock is added to the table. If there is a write lock, then this connection waits for the other connection to release the lock. If connection cannot get a lock for a specified time, then a lock timeout exception is thrown.

Usually, SELECT statement will generate read locks. This includes subqueries. Statements that modify data use write locks. It is also possible to lock a table exclusively without modifying data, using the statement SELECT ... FOR UPDATE. The statements COMMIT and ROLLBACK releases all open locks. The commands SAVEPOINT and ROLLBACK TO SAVEPOINT don't affect locks. The locks are also released when the autocommit
mode changes, and for connections with autocommit set to true (this is the default), locks are released after each statement. Here is an overview on what statements generate what type of lock:
 

Alex_winf01

Top Contributor
Ich habs einfach mal ausprobiert.

Code:
set autocommit off

1. Fenster:
Code:
Select ... For Update
Ergebnis: Datensatz wird angezeigt

2. Fenster:
Code:
Select ... For Update
Fehlermeldung wegen Zeitüberschreitung
 
G

Guest

Gast
maki hat gesagt.:
Dann zitieren wir mal alles und reissen nix aus dem Kontext:
:toll:
Warum du dich aber direkt angegriffen fühlst, bleibt mir ein Rätsel. :roll:
Ich habe nur die Sätze gesehen, die du hier gepostet hast. Der Teil mit dem "The database uses table level locks..." war nicht dabei...

Wie auch immer... Goosfraba! :D

@Alex_winf01
War ja auch klar, die Tabelle ist komplett gesperrt. ;)
 

ms

Top Contributor
Alex_winf01 hat gesagt.:
Fehlermeldung wegen Zeitüberschreitung
Wollte dich gerade darauf hinweisen.

Eine Transaktion bzw. eine Lock sollte immer so kurz wie möglich gehalten werden.
Die default-Timeouts diverser Datenbanken bewegen sich im Millisekunden - Sekundenbereich.
Lies dir nochmal die Stelle mit dem Locking durch, speziell gegen Ende steht genau dass, was dir gerade passiert ist.
Im übrigen hilft dir das Sperren mit SELECT FOR UPDATE nichts, da, wie beschrieben, bei autocommit = true (also ohne Transaktion) sowieso der lock bei jedem statement verloren geht. (Wenn ich es richtig verstanden habe).

Hibernate unterstützt übrigens auch SELECT FOR UPDATE wird aber nicht empfohlen.

Ich bin mir ehrlich gesagt noch nicht sicher was ich an deiner Stelle tun würde.
Es sieht für mich immer mehr nach einer speziellen Anforderung aus die man nicht durch ein Datenbank(standard)feature abdecken kann.
Was du auf jeden Fall brauchst sind Transaktionen (wenn nicht hier dann garantiert irgendwann in deinem Java-RDBMS-Entwickler-Leben)
Verwendest du Hibernate/JPA?
Dein erster Ansatz mit einer eigenen Spalte scheint doch nicht ganz so verkehrt.
Allerdings würde ich eine Spalte mit dem Benutzernamen oder ev. einem eindeutig generierten Token machen.
Der Datensatz bzw. die Datensätze (wenn es mehrere oder gejointe sind) müssen in einer Transaktion dem Benutzer zugeordnet werden. Gleichzeitig müsste es aber auch ein Timeout geben, dass den Datensatz wieder freigibt falls zB der Benutzer beim Bearbeiten einschläft, ...
Wenn der Benutzer in der Spalte steht hat der andere Benutzer gleich auch die Information wer denn gerade diesen Datensatz bearbeitet.

Vielleicht hat ja jemand noch einen besseren Vorschlag.

ms
 

ms

Top Contributor
Hier noch was Interessantes aus der H2-Doku:
Multi-Version Concurrency Control (MVCC)
The MVCC feature allows higher concurrency than using (table level or row level) locks. When using MVCC in this database, delete, insert and
update operations will only issue a shared lock on the table. Table are still locked exclusively when adding or removing columns, when dropping
the table, and when using SELECT ... FOR UPDATE. Connections only 'see' committed data, and own changes. That means, if connection A
updates a row but doesn't commit this change yet, connection B will see the old value. Only when the change is committed, the new value is
visible by other connections (read committed). If multiple connections concurrently try to update the same row, this database fails fast: a
concurrent update exception is thrown.
To use the MVCC feature, append MVCC=TRUE to the database URL:
jdbc:h2:~/test;MVCC=TRUE
Hilft dem Alex aber auch nicht bei seinem Problem.

ms
 
G

Guest

Gast
Ich würde eine Ad-hoc Lösung bevorzugen. Eine zusätzliche Tabelle, in der der User, die Zieltabelle und die Id(s) der
Datensätze vermerkt werden, die von einem User "exclusiv ausgecheckt" wurden (PK: Tabellenname + Datensatz-Id).
Dadurch bleibt das ursprüngliche Schema unangetastet. Alle Schreiboperationen gehen unter Berücksichtigung dieser
Tabelle.

Der Ablauf könnte wie folgt aussehen

1) SELECT FOR UPDATE für die Lock-Tabelle, auf den Datensatz, den ein Benutzer an sich krallen möchte.
1a) Kein Eintrag in der Lock-Tabelle vorhanden, dann ist der Datensatz noch nicht "ausgecheckt".
Für diesen Fall wird ein solcher angelegt. User + Tabelle + Id des Datensatzes + Datum oder was auch immer.
1b) Eintrag in der Lock-Tabelle vorhanden. Raus mit einer entsprechenden Meldung.

... usw. auch bei Updates. Prüfung, ob Datensatz gesperrt ist und wenn ja, ob vom gleichen Benutzer gesperrt oder
von einem anderen...

Das müsste aber ordentlich getestet werden.
 

Alex_winf01

Top Contributor
Vielen Dank an alle für die hilfreiche Diskussion. :D

@ Gast

genauso hatte ich es mir vorgestellt. Das natürlich ausreichend getestet werden muss, ist mir klar.
 

Alex_winf01

Top Contributor
Noch eine Frage:

Was mache ich für den Fall, wenn das Programm abschmiert? Angenommen Anwender A bearbeitet gerade Datensatz A. Datensatz A wird für die anderen Anwender gesperrt. Jetzt schmiert dem Anwender A das Programm ab.
 
G

Guest

Gast
Alex_winf01 hat gesagt.:
Noch eine Frage:

Was mache ich für den Fall, wenn das Programm abschmiert? Angenommen Anwender A bearbeitet gerade Datensatz A. Datensatz A wird für die anderen Anwender gesperrt. Jetzt schmiert dem Anwender A das Programm ab.
Dem Server (deiner Serveranwendung) ist sowas piepegal.
 

Alex_winf01

Top Contributor
@ Gust

ich nutze den Server-Modus von H2 und kein RMI (da nicht vom Kunden gewünscht) und das Problem bezog sich mehr auch auf das Problem mit der Datensatzsperrung. Beispiel: In der Tabelle für die Datensatzsperrung steht drin:

Anwener Datensatz inBearbeitung
Anwender A Datensatz 1 TRUE

Jetzt schmiert dem Anwender A das Programm ab. Dann steht da doch in der Spalte "inBearbeitung" true drin. Ich nutze Transaktionen.
 
G

Guest

Gast
Alex_winf01 hat gesagt.:
@ Gust

ich nutze den Server-Modus von H2 und kein RMI (da nicht vom Kunden gewünscht) und das Problem bezog sich mehr auch auf das Problem mit der Datensatzsperrung. Beispiel: In der Tabelle für die Datensatzsperrung steht drin:

Anwener Datensatz inBearbeitung
Anwender A Datensatz 1 TRUE

Jetzt schmiert dem Anwender A das Programm ab. Dann steht da doch in der Spalte "inBearbeitung" true drin. Ich nutze Transaktionen.
Wenn es abstürzt, wird die Transaktion nicht mit commit beendet und damit auch keine Änderung übernommen.
 

Alex_winf01

Top Contributor
Nur noch mal zum Verständnis:

Anwender A zeigt sich Datensatz A an. Anwender B soll sich jetzt Datensatz A noch nicht mal mehr anzeigen lassen. Es kommt eine Fehlermeldung "Dieser Datensatz wird gerade von Anwender A bearbeitet". Damit kein Anzeigen, kein bearbeiten, kein löschen.

Ist der Ansatz dann ok?
 

robertpic71

Bekanntes Mitglied
Alex_winf01 hat gesagt.:
Ist der Ansatz dann ok?

Kein Anzeigen finde ich etwas krass.. Aber es ist durchaus ein möglicher Ansatz, wenn auch nicht der empfohlene (man sollte keine Locks lange aufrecht erhalten, siehe auch ms). Aber in dem Fall ist die Alternative - eine logische Sperre (durch Datenfelder) auch nicht besonders schön.

Wir verwenden eigentlich bei uns entweder das optimistiche Locken oder die logische Sperre über eigene Felder. In deinem Fall heißt die Entscheidung pessim.Locken vs. logischer Sperre mit eigenen Feldern

Ich fasse mal kurz Vor- und Nachteile zusammen:

Sperre über Datenbank:
+ keine eigenen Felder notwendig
+ abgeschmierter Client wird irgendwann von der DB zurückgezogen
- kann sich negativ auf die Performance auswirken (Datenbank muss Sperren verwalten)
- auch SELECT muss mit Sperre arbeiten (damit man zur LockException gelangt) - Timeout setzen!
- langes Timeout --> lange Wartezeite für User, kurzes Timeout: unnötige Fehler bei z.B. Serverüberlastung
- kein teilweises Sperren/Updaten des Datensatzes möglich (eher Problem bei vorhandenen Datenbanken)
- Sperren meistens nicht vom Anwender entsperrbar

logische Sperre:
- eigene Felder notwendig
+ ein paar Felder mehr und man sieht wer den Datensatz sperrt
- wenn ein Client abschmiert, bleibt das Sperrflag stehen...
+ beim Lesen muss nicht gesperrt werden und auch keine Timeouts abgewartet werden
+ Benutzer können Sperren mit Programmhilfe ev. selber auflösen
+ Teilupdates möglich

nicht aufgeführt: optimistische Sperre (wäre wohl Sieger nach Punkten)

Zu den Feldern:
Wir verwenden für die logische Sperren meistens ein Statusfeld, welche nicht nur auf Bearbeitung stehen kann, sondern auch für storniert, fertig, unterbrochen usw. Zusammen mit anderen Feldern (letzter Sachbearbeiter, Timestamp letzte Bearbeitung) kann man bei einer Sperre auch sagen, wer den Datensatz sperrt. In Webanwendungen bzw. neuen Dateien, schreibe ich mir auch gerne die id zur Session als Sperrschalter. Wenn die Session ausläuft, entferne ich die logischen Sperren. Eine (selbst verwaltet) Sessiondatei hat bei Client/Server-Anwendungen seinen Reiz.

verlorene Sperrflags / Sperren
In beiden Fällen ist es wichtig bei allen Abbrüchen, Zurückbuttons usw. die Sperre wieder rückgängig zu machen. Bei der Datenbanksperre ist es etwas einfacher (ROLLBACK), bei der logischen Sperre den alten Status wiederherstellen. In beiden Fällen sind Programmfehler/abstürze (Exceptions!) ein Problem. Bei einem Programmfehler (Statement bleibt offen) kann auch die Datenbank nicht erkennen, dass die Sperre nicht mehr aktiv sein soll.

Auch wenn die Datenbanksperre weniger Arbeit und nach weniger Problemen aussieht, wäre das bei uns kein Option. Wenn man nicht weiß wer den Datensatz sperrt, muss man die Arbeitsplätze "durchgehen".

Ich persönlich würde mir eine Sessiondatei anlegen. Bei jeder Anmeldung wird eine Sessioneintrag für den Benutzer/IP-Adresse angelegen. Zu sperrende Sätze mit der SessionId (als Sperrschalter) versehen und zum Entsperren wieder gelöscht. Beim Abmelden die (übergebliebene) Sperren der Session entfernen und den Sessionsatz löschen bzw. auf inaktiv setzen.

Wenn es beim Anmelden mit der Kombination User/Ip-Adresse bereits eine aktive Session gibt, könnte man nach Rückfrage die Aufheben (Problem bei dir: normalerweise ist IP/Benutzer recht eindeutig, bei einem Terminalserver haben alle Benutzer die gleiche IP). Alternativ könnte ein Superuser auch Sessions löschen.


noch zu den Teilupdates: vermeide das Mischen von Stammdaten und Bewegungsdaten. Beispiel: Bei unserem Artikelstamm (Datenbankdesign > 20 Jahre) gibt die die Stammdaten und Felder für die letzte Bestellung und den Gesamtlagerstand usw. Nach aktuellen Sperrmechanismen ist das totaler Mist. Wenn jemand im Artikelstammblatt ist, und der Artikel inzwischen verkauft wird... Da gibt dann die Notwendigkeit einer logischen Sperre (nur für den Stammblattteil). Aber du hast sicher nicht > 1000 Cobolprogramme an der Datenbank hängen ;-) und kannst die DB vernünftig designen.


/Robert
 

ms

Top Contributor
@Alex, dein Problem mit dem Aufheben der Sperre ist, dass du immer schreibst, es gibt keinen Applikationsserver der zwischen Datenbank und Client stehen darf. Habe ich dich richtig verstanden? Wenn ja, wer soll denn die Sperre aufheben?
Wenn du es über eigene Felder machst (ich weis eigentlich noch immer nicht wofür du dich jetzt entschieden hast) dann brauchst du jemand oder etwas, der/das die Sperren überwacht und gegebenenfalls wieder freigibt.

ms
 

Alex_winf01

Top Contributor
Habs mit den zusätzlichen Spalten hinbekommen.

Jetzt habe ich noch eine folgende Frage:

In der Dokumentation steht:

Table Level Locking

The database allows multiple concurrent connections to the same database. To make sure all connections only see consistent data, table level locking is used by default. This mechanism does not allow high concurrency, but is very fast. Shared locks and exclusive locks are supported. Before reading from a table, the database tries to add a shared lock to the table (this is only possible if there is no exclusive lock on the object by another connection). If the shared lock is added successfully, the table can be read. It is allowed that other connections also have a shared lock on the same object. If a connection wants to write to a table (update or delete a row), an exclusive lock is required. To get the exclusive lock, other connection must not have any locks on the object. After the connection commits, all locks are released. This database keeps all locks in memory.

Nun habe ich da ein kleines Verständnisproblem. 2 Anwender bearbeiten 2 unterschiedliche Datensätze und klicken gleichzeitig auf speichern. Es wird ein update bei jedem Anwender durchgeführt. Beim ersten Anwender klappt das ja vielleicht noch ganz gut, beim zweiten kann es doch aufgrund des Table Level Locking ein Problem geben. Wäre da vielleicht folgendes eine Lösung:

Lock Timeout

If a connection cannot get a lock on an object, the connection waits for some amount of time (the lock timeout). During this time, hopefully the connection holding the lock commits and it is then possible to get the lock. If this is not possible because the other connection does not release the lock for some time, the unsuccessful connection will get a lock timeout exception. The lock timeout can be set individually for each connection
 

Alex_winf01

Top Contributor
Mein Problem ist das Table Level Locking. Bei einer Mehrbenutzeranwendung speichern mehrere Anwender gleichzeitig unterschiedliche Datensätze speichern. Da ist das Sperren der ganzen Tabelle sch....

Das heisst, Anwender A speichert gerade Datensatz A, gleichzeitig speichert Anwender B den Datensatz B. Beim Update für Anwender A wird die Tabelle gesperrt, Anwender B kann nicht mehr speichern. Wie kann ich das verhindern? Ist da Lock Timeout eine Lösung?

Ich möchte ja, dass mehrere Anwender gleichzeitig in die gleiche Tabelle speichern können (halt unterschiedliche Datensätze).
 
M

maki

Gast
Ein (richtiges) Client Server System wäre wahrscheinlich besser gewesen als einzelne Anwedungen die alle auf eine DB schreiben.

Auch wäre eine bessere DB (eine, die Rowlocking unterstützt) nicht verkehrt.
 

ms

Top Contributor
Kannst du vielleicht kurz zusammenfassen was aus dem bisher gesagten du jetzt wie einsetzt/behandelst?
Eigenes Feld in der Tabelle?
Verwendest du jetzt Transaktionen oder nicht?
Und wenn ja, für welche Zugriffe/Änderungen?
Wofür willst du genau das Locktimeout einsetzen?

ms
 

Alex_winf01

Top Contributor
Also ich nutze den H2-Server Modus, transaktionen für insert, update, delete. Das Problem mit dem Gleichen Datensatz bearbeiten löse ich über zusätzliche Spalten (inBearbeitung, Anwender, Tabelle, seit_wann_in_Bearbeitung).

@ ms

Mein einzigstes Problem ist jetzt nur noch folgendes: Wenn mehrere Anwender gleichzeitig auf speichern gehen und ein update an unterschiedlichen Datensätzen durchführen, wird beim ersten Anwender die Tabelle gesperrt. Siehe mein Posting mit dem Table Level Locking. Ich möchte natürlich, dass alle Anwender ihre Datensätze in die gleiche Tabelle speichern können. Wie kann ich das machen? Ein Timeout für das Lock?
 

ms

Top Contributor
Die Transaktion bzw. der Lock existiert doch nur für die Zeit wo du das Update-Statement durchführst ev. auch über mehrere Statements, also sehr sehr kurz. Somit muss halt die zweite Transaktion ev. kurz warten. Das sollte keine Probleme machen wenn du auch im Programm dafür sorgst, dass die Transaktion bzw. der Lock sehr kurz existiert.
Der Standardwert für DEFAULT_LOCK_TIMEOUT beträgt 5sec, das reicht auf jeden Fall.

ms
 

Alex_winf01

Top Contributor
Und genau die 5 Sekunden sind mein Problem. Wenn innerhalb dieser 5 Sekunden ein 2. Anwender auf speichern klickt, wird er eine Fehlermeldung bekommen, dass die Tabelle komplett gesperrt ist.
 

ms

Top Contributor
Nimmst du diese Erkenntnis aus einem Test den du gemacht hast?

Es wird nicht die Datenbank für 5 Sekunden gesperrt sondern wenn nach 5 sec der Lock nicht freigegeben wird => also eine andere Transaktion länger als das Timeout benötigt.

Du brauchst nur dafür zu sorgen, dass deine Transaktionen nicht länger wie das angegebene Timeout dauern, dann gibt es keine Probleme.
Natürlich können auch 5sec zuwenig sein, kommt darauf an wieviele Benutzer gleichzeitig wieviele Datensätze in einer Transaktion aktualisieren bzw. wie lange deine Insert-Update-Delete-Statements dauern. Dann kann man dieses Timeout etwas anheben. Das sind aber Maßnahmen die man eventuell im Zuge von Lasttests machen kann. Zum jetzigen Zeitpunkt wo du von nur 2 Benutzern redest und grundsätzlich mal das Funktionsprinzip realisieren willst ist das kein Thema.

Edit:
Das DEFAULT_LOCK_TIMEOUT beträgt nur 1sec und auch das sollte im Normalfall reichen.

ms
 

Alex_winf01

Top Contributor
@ ms

natürlich ist nicht die ganze Datenbank gesperrt, sondern nur die entsprechende Tabelle, auf die der insert, update, delete-Befehl durchgeführt wird.

Ich weiss nicht, ob wir aneinander vorbei reden. Ich gehe etwa von 50 Anwendern aus. Jeder gibt Daten über die GUI ein und drückt auf speichern. Die Schaltfläche speichern ruft bei mir aus der Datei Update.java die entsprechende Methode zum speichern auf. Das Update wird natürlich innerhalb einer Transaktion durchgeführt.

Nun speichert irgendein 2. Anwender seine Daten aus einem anderen Datensatz und klickt gleichzeitig auf speichern. Nun habe ich 2 X ein
Code:
update tabelle set abc = '' where id = ''
mit 2 Transaktionen gleichzeitig.Die tabelle ist aber für einen kurzen Moment aufgrund der 1. Transaktion gesperrt. Der 2. Anwender bekommt dann doch die Fehlermeldung einer Zeitüberschreitung. :(

Oder befinde ich mich da auf dem Holzweg?
 

robertpic71

Bekanntes Mitglied
Alex_winf01 hat gesagt.:
Mein einzigstes Problem ist jetzt nur noch folgendes: Wenn mehrere Anwender gleichzeitig auf speichern gehen und ein update an unterschiedlichen Datensätzen durchführen, wird beim ersten Anwender die Tabelle gesperrt. Siehe mein Posting mit dem Table Level Locking. Ich möchte natürlich, dass alle Anwender ihre Datensätze in die gleiche Tabelle speichern können. Wie kann ich das machen? Ein Timeout für das Lock?

Ich glaube dir fehlt ein Commit (Autocommit aus?). Wenn du die Daten per Feldwert sperrst, brauchst das Locking ja nicht aufrecht zu erhalten!

möglicher Ablauf:

Benutzer wählt den Datensatz zur Bearbeitung an
1.) einlesen/prüfen
SELECT der Daten
prüfen ob Sperrschalter sitzt
wenn ja --> Fehlermeldung
wenn nein --> UPDATE Sperrfelder, COMMIT (*)

Damit gibt es keine Datenbanksperre. Andere Jobs können verzögerungsfrei auf den
Datensatz zugreifen und am Sperrschalter erkennen, von wem er gesperrt ist.

(*) Theoretisch könnte sich der Datensatz zwischen SELECT (ohne Sperre) und UPDATE ändern.
Dies kann z.B. durch eine Where Abfrage auf Sperrschalter = false im Update geprüft werden.

2a.) Wenn der Benutzer die Daten geändert hat
UPDATE, Sperrfelder löschen und COMMIT

2b.) Wenn der Benutzer abbricht, Sperrfelder löschen, COMMIT

Bei diese Lösung gibt es nie Sperren die auf eine Benutzerreaktion warten. Die Sperrdauer sollte sich im Millisekundenbereich bewegen.

maki hat gesagt.:
Auch wäre eine bessere DB (eine, die Rowlocking unterstützt) nicht verkehrt.
H2 bietet auch eine alternative Sperrlogik (MVCC) an. Hier bleibt der Satz immer lesbar. Das ist mMn meistens nicht Notwendig (optimitic Locking!) oder so wie hier: logische Sperren über Felder.

maki hat gesagt.:
Ein (richtiges) Client Server System wäre wahrscheinlich besser gewesen als einzelne Anwedungen die alle auf eine DB schreiben.
Ich ziehe eine Serverlösung (Programmier- und wartungstechnisch) jeder Server/Client-Anwendung vor. Allerdings habe ich schon einige Lösungen mit Clients und direkter Datenbankanbindung gemacht (die meisten noch vor Java). Das kann genauso problemlos laufen wie Serveranwendungen oder Clients mit Servercalls - ist aber sicher etwas anfälliger.

/Robert
 

ms

Top Contributor
Alex_winf01 hat gesagt.:
Die tabelle ist aber für einen kurzen Moment aufgrund der 1. Transaktion gesperrt.
Richtig, aber dieser Moment ist so kurz, sodass im Normalfall ein Timeout von wenigen Sekunden ausreicht.

Alex_winf01 hat gesagt.:
Der 2. Anwender bekommt dann doch die Fehlermeldung einer Zeitüberschreitung. :(
Probier es doch bitte endlich aus anstatt hier laufend Mutmaßungen anzustellen.

ms
 
T

Thomas Müller

Gast
Hallo - also H2 unterstützt nur Table Level Locking, und bisher kein Row Level Locking. Das mit FOR UPDATE stimmt schon, das sperrt die ganze Tabelle. Allerdings ist auch Multi-Version Concurrency Control eingebaut (im Moment Beta).
 
G

Gast

Gast
Ja, Row Level Locking ist geplant für dieses Jahr, aber Priorität hat im Moment MVCC.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
sparrow Wie würdet ihr vorgehen: Datensatzsperrung (mit Hibernate) Datenbankprogrammierung 4
S Datenbankprogrammierung in Java unter NetBeans 12 funktioniert nicht! Datenbankprogrammierung 1
thet1983 MySQL ODBC Driver zuweisen unter Mac OX Mav Datenbankprogrammierung 2
F Oracle Oracle JDBC Anbindung unter Glassfish 3.1.2 Datenbankprogrammierung 3
F SQLite-Extensions unter Java Datenbankprogrammierung 2
GianaSisters MS SQL unter Netbeans OK - nach konvertieren Absturz Datenbankprogrammierung 6
S Firebird NoClassDefFoundError trotz erfolgreichem Class.forName(...) unter Linux Datenbankprogrammierung 5
A Leeres ResultSet mit H2 unter Vista Datenbankprogrammierung 3
feuervogel SQLite unter Linux mit Eclipse einrichten Datenbankprogrammierung 8
D mySQL emullierte PreparedStatements haben Fehler unter Last Datenbankprogrammierung 3
S PreparedStatements, Abfrageoptimierung unter MS Access Datenbankprogrammierung 5
D Datenbankanbindung unter Linux Datenbankprogrammierung 10
G anbindung an sqlserver unter windows Datenbankprogrammierung 7
N classpath für jdbc unter xp Datenbankprogrammierung 2
Z Verbindung unter Linux erstellen Datenbankprogrammierung 2
K Datenbankeinbindung unter Java Datenbankprogrammierung 6
K Problem mit datenbankanbindung unter access 2003 Datenbankprogrammierung 3
G Java-Security Permission (?) mit Tomcat unter Unix-Debian Datenbankprogrammierung 3
D JDBC unter Java ME Datenbankprogrammierung 4
J PLatzhalter unter SQL mit Java und Access Datenbankprogrammierung 2
T Access-Datenbank unter Mac OS X Datenbankprogrammierung 14
S MySQL-Abfrage unter java funktioniert nicht! Datenbankprogrammierung 4
J JDBC installieren unter win xp(mysql), bitte kurze anleitung Datenbankprogrammierung 6
Z jdbc-Verbundung unter Windows zur Postgresql DB sehr langsam Datenbankprogrammierung 3
L Installation des Treibers unter Windows XP Datenbankprogrammierung 10
D Access-Datenbank unter Java verwenden Datenbankprogrammierung 7
N Schritt für Schitt Tutorial für Java und JDBC unter Linux Datenbankprogrammierung 4
A MYSQL Datenbankzugriff unter Linux Datenbankprogrammierung 3
L INSERT INTO - Problem unter Java Datenbankprogrammierung 8
D Wie füge ich mit dem Database Connector etwas hinzu. Datenbankprogrammierung 1
berserkerdq2 database is closed, obwohl ich alle statements in try catch blöcken habe? Datenbankprogrammierung 5
T The database file is locked Datenbankprogrammierung 2
Kirby.exe Sample Database in Postgres laden Datenbankprogrammierung 5
C Java MySQL check if value exists in database Datenbankprogrammierung 2
C Problem with insertion in database. Datenbankprogrammierung 7
B MySQL Data Tools Plattform - "Database Connections" findet den Treiber nicht Datenbankprogrammierung 1
L MySQL Database Helper Klasse mit Consumer Datenbankprogrammierung 7
J Java 8 und Microsoft Access Database-Dateien(mdb) Datenbankprogrammierung 1
M Derby/JavaDB Drop Database problem Datenbankprogrammierung 3
C Problem oder Denkfehler mit H2-Database Datenbankprogrammierung 3
S Oracle Database 11g , eclipse , Tabelle erstellen Datenbankprogrammierung 2
P Embedded Database und große Datenmengen Datenbankprogrammierung 23
G Database indexing Datenbankprogrammierung 7
B H2 Database Beispiel Source Code Datenbankprogrammierung 8
H hsqldb - Database must be shutdown Datenbankprogrammierung 10
A Fehlermeldung H2 Database Datenbankprogrammierung 3
A Fehler beim Starten des Servers für H2 Database Datenbankprogrammierung 13
G Import einer csv-Datei in eine H2-Database Datenbankprogrammierung 12
J Database replication Datenbankprogrammierung 4
E Problem beim laden des JDBC Driver bzw der Database Datenbankprogrammierung 8
J Hibernate create database Datenbankprogrammierung 4

Ähnliche Java Themen


Oben