jpa "pessimistic lock" funktioniert nicht?!

dermoritz

Bekanntes Mitglied
ich versuche gerade eine Art Bearbeitungsfunktion für eine JPA-Klasse (Eclipselink 2.0) zu bauen. Diese soll per pessimistic lock versehentliches bearbeiten von mehreren Personen unterbinden:
Code:
tx.begin();
		em.lock(Eintrag, LockModeType.PESSIMISTIC_WRITE);
		assertEquals(LockModeType.PESSIMISTIC_WRITE, em.getLockMode(Eintrag));
		Eintrag.setKommentar("rülps");
		Eintrag.setImage("rälps");
			try {
				Thread.sleep(20000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		tx.commit();
Das sleep hab ich eingebaut um den Lock zu überprüfen: ich versuche die Daten per sql zu ändern. Meine Vorstellung ist nun, dass der MySql Server eine Fehlermeldung ausspuckt tut er aber nicht. Das verhalöten ist das selbe wie ohne Lock?!
Was mach ich falsch?
 
S

SlaterB

Gast
kann es sein, dass das Locking nur innerhalb des JPA-Frameworks auf Java-Ebene stattfindet und die DB gar nicht betrifft?
teste doch mit zwei Java-Zugriffen durcheinander

'pessimistic lock mysql' bei google findet nicht viel..
 

dermoritz

Bekanntes Mitglied
ich verwende "innoDB" meintest du das?

EDIT: ich hab auch mal in das MySql-Log geschaut: dort wird brav ein "Select-for-update" Statement abgesetzt. Nun hab ich mal während des sleeps die DB geändert. Das komische ist im DB-Log sieht es so aus als würde ich per Programm die externe Änderung durchführen: also innerhalb der Transaktion die ich in Java starte kann ich Änderungen durchführen.
Für die Änderungen die das Java durchführt werden dann seperate Statements ohne Transaktion ausgeführt. - was soll das? wieso kann ich die Transaktion des Javaprogramms "kapern"?

Das mit dem sleep ist natürlich auch nicht das gelbe vom EI. Wie kann ich denn mehrere gleichzeitige Zugriffe simulieren? Brauch ich da extra Threads? Und wie synchroniere ich die, dass die Zugriffe auch gleichzeitig sind?
 
Zuletzt bearbeitet:

Niki

Top Contributor
probiers einfach mal direkt in der datenbank aus mit einem select for update, wenn ers dort auch einfach schluckt weißt du, dass es an der datenbank liegt
 

dermoritz

Bekanntes Mitglied
wie stell ich das denn in der db an (ich verwende mysql-workbench)? irgendwie brauche ich ja 2 Verbindungen. Die eine muss ein select for update machen und vorher eine transaktion beginnen. Dann muss die andere Verbindung ein Update machen und dann muss die erste die Transaktion beenden. - wie macht man denn das?
(mit Verbindung1=java und Verbindung2=MysqlWorkbench hab ich wie gesagt genau das nachvollzogen)
 

dermoritz

Bekanntes Mitglied
ok ich hab das ganze mal mit 2 Kommandozeilen nachvollzogen. Ganz so kaputt scheint es nicht: solange die Transaktion für das Select on Update offen ist wird das update der 2. Kommandozeile nicht ausgeführt. Aber in dem Moment in dem in der ersten ein commit kommt wird das 2. update auch ausgeführt.
Das Lock kümmertsich als nur um die Reihenfolge, was aber gar nix nützt. Denn man hat wieder eine Racecondition nur ist Sie andersherum: der der zuerst das Lock bekommt verliert -(dessen Änderungen gehen verloren).

Mir wär es recht wenn das Lock auch das lesen sperren würde oder zumindest das absetzen von Update statements - geht das?
 

dermoritz

Bekanntes Mitglied
ok ich glaub ich kann mit der Art des Locks ganz gut leben. Nur brauche ich einen Timeout für das locking. Das Problem ist: aus irgendeinem Grund wird "javax.persistence.lock.timeout" ignoriert. (egal ob als
Code:
Map<String,Object> props = new HashMap<String, Object>();
props.put("javax.persistence.lock.timeout", 3000);
em.find(tabelle.class, id,LockModeType.PESSIMISTIC_WRITE,props);
oder als
Code:
<property name="javax.persistence.lock.timeout" value="3000"/>
hat jemand ne ahnung wieso? bzw. wie man ein timeout sonst setzen kann?)
 

JanHH

Top Contributor
Ich hab jetzt auch mal sowas gemacht (siehe entsprechender Thread), mir ist aufgefallen dass man die Entity-Klasse "versioned" machen muss, also eine int-Property mit @Version annotieren.
 
Zuletzt bearbeitet:

dermoritz

Bekanntes Mitglied
Für ein pessimistic lock braucht man nicht unbedingt versioning. Denn dort wird der Lock direkt in der Datenbank geholt bevor irgendwelche setter Objekte verwenden. Damit kann man dann auch sicher sein das im Moment des commit die Version im Spiecher der Version in der DB entspricht.
Das funktioniert bei mir auch einwandfrei, nur muss der User im Falle er will ein Lock für ein gelocktes Objekt 50s warten bis er weiterarbeiten kann. Und diese 50s kann man anscheinend erst ab einer InnoDB version 1.01 oder so pro Session setzen.
 

gumi

Mitglied
Hi dermoritz,
hast Du dein Problem gelöst?
ich stehe gerade selbst vor einem ähnliches Problem. Wollte das ganze auch über javax.persistence.lock.timeout lösen, aber egal wie viele mils. ich eingebe das timeout brauch immer eine halbe Ewigkeit bis es hochkommt. Es wäre super wenn Du ein Tip für mich hast, oder gibt es eine andere Möglichkeit herauszufinden ob ein lock schon gesetzt ist.
Vielen Dank im voraus.
 

Ähnliche Java Themen


Oben