JPA PESSIMISTIC locking

G

Gast2

Gast
Hallo zusammen,

Ich habe eine Eingabemaske um Personen zu speichern/ändern. Wenn nun 2 User einen Datensatz ändern speichert er den Datensatz der zuletzt kommt. Das will ich vorher schon verhindern, in dem es einen Bearbeitungsmodus gibt wo die Felder aktiv sind und indem NUR 1 User drin sein kann und einen lock auf den Datensatz hat.
Ein 2ter User sieht den Datensatz nur als readonly und kanndie Daten lesen aber nicht ändern.
Irgendwie klappt das aber mit dem PESSIMISTIC locking nicht so recht.

Java:
	public Object find(Class<?> entityClass, Object primaryKey) {
		LockModeType lockMode = LockModeType.PESSIMISTIC_WRITE;
		return entityManager.find(entityClass, primaryKey, lockMode);
		Object  object =  entityManager.find(entityClass, primaryKey);
		entityManager.refresh(object, lockMode);
return object;
	}

1.Wenn ich jetzt ein Objekt mit dem LockType refreshe. Und ein anderer User ein Objekt mit der gleichen ID speichern will, müsste doch eine Exception bekommen oder?

2. Kann man flag im Objekt setzen welches OR Mapper automatisch beim find füllt, dass man weiß ob das Objekt gelockt ist? irgendwie sowas wie readonly? Gibt es sowas oder müsste man so ein Feld selbst füllen?

3. Falls bei 2 nix gibt hab ich mir vorgestellt User 1 klickt auf bearbeiten alle Felder sind aktiv Datensatz wird gelockt. 2 User klickt auf bearbeiten bekommt eine Exception "Anderer User bearbeitet den Datensatz" und kann die Daten nur mit inaktiven Felder anschauen?.

Gruß
 

KSG9|sebastian

Top Contributor
Verwende doch OptimisticLocking per Versions-Attribut?


Die JavaDoc beschreibt relativ genau was passiert mit den LockModes:
If transaction T1 calls lock(entity, LockModeType.READ) on a versioned object, the entity manager must ensure that neither of the following phenomena can occur:

P1 (Dirty read): Transaction T1 modifies a row. Another transaction T2 then reads that row and obtains the modified value, before T1 has committed or rolled back. Transaction T2 eventually commits successfully; it does not matter whether T1 commits or rolls back and whether it does so before or after T2 commits.
P2 (Non-repeatable read): Transaction T1 reads a row. Another transaction T2 then modifies or deletes that row, before T1 has committed. Both transactions eventually commit successfully.
Lock modes must always prevent the phenomena P1 and P2.

In addition, calling lock(entity, LockModeType.WRITE) on a versioned object, will also force an update (increment) to the entity's version column.


Variante 3 würde ich nicht empfehlen denn du kannst nie zu 100% garantieren das der Datensatz entsperrt wird. Wenn irgendwelche Fehler auftreten hast du Datensätze welche ewig gesperrt sind.
 
G

Gast2

Gast
Ja ich will kein Optimisitc Locking, da sonst ein Benutzer Daten ändern kann und die eventuell nimmer speichern da die Version nicht mehr stimmt. Dann muss er seine Änderungen wegschmeißen oder ich muss ein merge Dialog anbieten...

Wenn ich das richtig verstanden hab funktioniert Pessimistic locking auch nur mit Versions-Attribut...
 

KSG9|sebastian

Top Contributor
Ich glaube das dir Locking hier allgemein nicht viel helfen wird.

Objekte werden nur für eine Transaktion gesperrt. Ich glaube aber kaum das der Transaktionsscope so groß ist wie du ihn benötigen würdest.

In deinem Fall müsste ja folgendes passieren:

1. Transaktion öffnen
2. Objekt lesen
3. Objekt sperren
4. Objekt zum Client
5. Objekt bearbeiten
6. Objekt zum Server
7. Objekt innerhalb der Transaktion (1) speichern
8. Transaktion committen
9. Objekt ist wieder entsperrt


Was du benötigst wäre ein globaler Lock auf ein Entity, was wahrscheinlich nur über Eigenimplementierung möglich ist.
Allerdings, wie schon gesagt, würde ich davon klar abraten, denn du kannst nie garantieren dass dieses Objekt wieder entsperrt wird.
Irgendwann kommst du dann an einen Punkt an dem ein Admin händisch eingreifen muss weil wieder irgendwo PCs abgestürzt sind oder User nicht auf "abmelden" geklickt haben. Irgendwann ist der Admin dann ausgelastet und du musst dir halbgare Algorithmen ausdenken nach denen Objekte wieder entsperrt werden.

Ich glaube der einfachere Weg hier ist entweder über Meldungen zu arbeiten: "Achtung, das Objekt wird gerade von jemand bearbeitet". Allerdings ist die Frage ob das wirklich jemand interessiert. Zusätzlich musst du diese Funktionalität natürlich auch selbst implementieren.

Oder eben doch Variante 3: Optimistic Locking. Zur Not bei einem Konflikt das "neue" Objekt laden und dem User seine Änderungen daneben stellen.

Und die Frage ist natürlich auch wie oft das denn vorkommen wird? Wir betreuen eine Anwendung auf der ca. 120.000 User arbeiten. Bei einigen Kunden arbeiten mehrere Hundert Mitarbeiter auf denselben Daten und selbst da kommt dieses Problem "relativ" selten vor.
 
G

Gast2

Gast
Mhm dachte die entity ist auf DB ebene gelockt sowas wie "update nowait" und nicht nur in der Transaktion.

Das heißt nach einem commit wären alle locks wieder weg.
Ja kommt realtiv oft vor... Und optimistic locking ist wie gesagt nervig und ein merge dialog kann auch aufwändig werden.
 
G

Gast2

Gast
Okay werd ich mir mal anschauen danke =)...

Aber ich versteh trotzdem meine Denkfehler oben nicht =)... Aber vielleicht -muss nochmal nachlesen- benötige ich auch pessimistic locking eine version-attribut.
 

Ähnliche Java Themen


Oben