2017-10-18 6 views
5

Ich habe eine Menge Beiträge zu diesem Thema gefunden, aber alle Antworten waren nur Links zu Dokumentationen ohne Beispielcode, d. H. Wie man Parallelität in der Praxis verwendet.Parallelität mit Hibernate im Frühjahr

Meine Situation: Ich habe eine Entität House mit (für simplification) zwei Attribute, number (die ID) und owner. Die Datenbank wird initialisiert mit 10 Houses mit number 1-10 und owner immer null.

Ich möchte dem Haus einen neuen Besitzer zuweisen, der momentan keinen Besitzer hat, und den kleinsten number. Mein Code sieht wie folgt aus:

@Transactional 
void assignNewOwner(String newOwner) { 
    //this is flagged as @Transactional too 
    House tmp = houseDao.getHouseWithoutOwnerAndSmallestNumber(); 

    tmp.setOwner(newOwner); 

    //this is flagged as @Transactional too 
    houseDao.update(tmp); 
} 

Für mein Verständnis, obwohl der @Transactional verwendet wird, die gleiche House verschiedenen Eigentümern doppelt vergeben werden könnten, wenn zwei Anfragen die gleichen leeren House wie tmp holen. Wie kann ich sicherstellen, dass dies nicht passieren kann?

Ich weiß, einschließlich der Aktualisierung in der Auswahl der leeren House würde das Problem lösen, aber in naher Zukunft möchte ich ändern/arbeiten mit dem tmp Objekt mehr.

+1

Das 'houseDao.update (tmp);' ist unnötig, da 'tmp' eine verwaltete Entität ist (Sie befinden sich in einer transaktionalen Methode). Die Änderungen werden beibehalten, ohne dass ein separates 'update()' benötigt wird. – Kayaman

Antwort

1

optimistisch

Wenn Sie eine Version Spalte zu Ihrem Unternehmen/Tabelle hinzufügen dann können Sie die Vorteile eines Mechanismus zum optimistischen Sperren nehmen könnte. Dies ist der beste Weg, um sicherzustellen, dass sich der Zustand einer Entität nicht geändert hat, seit wir sie in einem Transaktionskontext erhalten haben.

Sobald Sie createQuery mit der session können Sie dann rufen setLockMode(LockModeType.OPTIMISTIC);

Dann, kurz bevor die Transaktion verpflichtet ist, würde die Persistenz-Provider für die aktuelle Version dieser Einheit abzufragen und überprüfen, ob sie durch eine andere Transaktion erhöht wurde . Wenn dies der Fall ist, erhalten Sie eine OptimisticLockException und einen Transaktions-Rollback.

Pessimistische

Wenn Sie Ihre Zeilen nicht Version tun, dann werden Sie mit pessimistischen lockin links was im Grunde bedeutet, dass Sie phycically eine Sperre für Abfragen Einheiten auf Datenbankebene und andere Transaktionen erstellen nicht/aktualisieren lesen können diejenigen, bestimmte Zeilen.

Sie das erreichen, indem sie diese auf dem Query Objekt einstellen:

setLockMode(LockModeType.PESSIMISTIC_READ);

oder

setLockMode(LockModeType.PESSIMISTIC_WRITE);

1

Eigentlich ist es ziemlich einfach - zumindest meiner Meinung nach, und ich abstrahieren werde weg von dem, was Hibernate wird generiert, wenn Sie Pessimistic/Optimistic sagen. Sie könnten denken, das ist SELECT FOR UPDATE - aber es ist nicht immer der Fall, MSSQL AFAIK hat das nicht ...

Diese sind JPA Annotationen und sie garantieren einige Funktionalität, nicht die Implementierung.

Grundsätzlich sind sie ganz andere Dinge - PESSIMISTIC vs OPTIMISTIC Verriegelung. Wenn Sie eine pessimistische Sperrung machen, tun Sie zumindest eine logische synchronized block - Sie können tun, was Sie wollen, und Sie sind im Rahmen der Transaktion sicher. Nun, was auch immer das Schloss für die row, table or even page gehalten wird, ist nicht spezifiziert; also ein bisschen gefährlich. Normalerweise kann die Datenbank Locks eskalieren, MSSQL macht das, wenn ich wieder richtig rufe.

Offensichtlich Sperre verhungern ist ein Problem, so dass Sie vielleicht denken, dass OPTIMISTIC Locking helfen würde. Als eine Randnotiz ist dies, was transactional memory is in modern CPU; Sie benutzen den gleichen Denkprozess.

So optimistisch Sperren ist wie sagen - ich werde diese Zeile mit einer ID/Datum usw. markieren, dann werde ich einen Schnappschuss davon machen und damit arbeiten - bevor ich festlege, werde ich überprüfen, ob diese ID geändert hat. Offensichtlich gibt es Streit auf diesem ID, aber nicht auf den Daten. Wenn es sich geändert hat - abbrechen (aka werfen OptimisticLockException) sonst begehen die Arbeit.

Die Sache, die alle IMO stört ist, dass OptimisticLockException - wie Sie davon erholen? Und hier ist etwas, was Sie nicht mögen werden - es kommt darauf an. Es gibt Apps, bei denen eine einfache Wiederholung ausreichen würde, es gibt Apps, bei denen dies unmöglich wäre. Ich habe es in seltenen Szenarien verwendet.

Ich gehe normalerweise mit Pessimistic Verriegelung (es sei denn Optimistic ist total keine Option). Gleichzeitig würde ich schauen, was Hibernate für diese Abfrage generiert. Zum Beispiel benötigen Sie möglicherweise eine index auf, wie der Eintrag für die DB abgerufen wird, um nur die Zeile zu sperren - denn das ist letztlich das, was Sie wollen.

Verwandte Themen