Für Spring Data 1.6 oder höher
@Lock
wird auf CRUD-Methoden ab Version 1.6 von Spring Data JPA unterstützt (tatsächlich gibt es bereits einen Meilenstein
verfügbar). Siehe dieses Ticket
für weitere Details.
Mit dieser Version deklarieren Sie einfach Folgendes:
interface WidgetRepository extends Repository<Widget, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Widget findOne(Long id);
}
Dadurch wendet der CRUD-Implementierungsteil des unterstützenden Repository-Proxys den konfigurierten LockModeType auf find(…)
an Rufen Sie den EntityManager
auf .
Andererseits
Für frühere Version von Spring Data 1.6
Das pessimistische @Lock
von Spring Data Anmerkungen gelten nur (wie Sie darauf hingewiesen haben) für Abfragen. Mir sind keine Anmerkungen bekannt, die sich auf eine gesamte Transaktion auswirken können. Sie können entweder ein findByOnePessimistic
erstellen Methode, die findByOne
aufruft mit einem pessimistischen Schloss oder Sie können findByOne
ändern um immer eine pessimistische Sperre zu erhalten.
Wenn Sie Ihre eigene Lösung implementieren möchten, könnten Sie dies wahrscheinlich tun. Unter der Haube das @Lock
Anmerkung wird von LockModePopulatingMethodIntercceptor
verarbeitet was folgendes bewirkt:
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
Sie könnten einen statischen Sperrmanager erstellen, der einen ThreadLocal<LockMode>
hatte Member-Variable und haben dann einen Aspekt, der um jede Methode in jedem Repository gewickelt ist, die bindResource mit dem in ThreadLocal festgelegten Sperrmodus aufgerufen hat. Auf diese Weise können Sie den Sperrmodus für einzelne Threads festlegen. Sie könnten dann Ihren eigenen @MethodLockMode
erstellen Anmerkung, die die Methode in einen Aspekt einschließen würde, der den Thread-spezifischen Sperrmodus vor dem Ausführen der Methode setzt und ihn nach dem Ausführen der Methode löscht.
Ressourcenlink:
- Wie aktiviere ich LockModeType.PESSIMISTIC_WRITE beim Suchen von Entitäten mit Spring Data JPA?
- So fügen Sie benutzerdefinierte hinzu Methode zu Spring Data JPA
- Spring Data Pessimistic Lock Timeout with Postgres
- JPA-Abfrage-API
Verschiedene Beispiele für pessimistische Sperrzeitüberschreitung
Setzen einer pessimistischen Sperre
Ein Entity-Objekt kann explizit durch die Lock-Methode gesperrt werden:
em.lock(employee, LockModeType.PESSIMISTIC_WRITE);
Das erste Argument ist ein Entitätsobjekt. Das zweite Argument ist der angeforderte Sperrmodus.
Eine TransactionRequiredException
wird ausgelöst, wenn beim Aufrufen von lock keine aktive Transaktion vorhanden ist, da explizites Sperren eine aktive Transaktion erfordert.
Eine LockTimeoutException
wird ausgelöst, wenn die angeforderte pessimistische Sperre nicht gewährt werden kann:
- Ein
PESSIMISTIC_READ
Die Sperranforderung schlägt fehl, wenn ein anderer Benutzer (der durch eine andere EntityManager-Instanz repräsentiert wird) derzeit einenPESSIMISTIC_WRITE
besitzt dieses Datenbankobjekt sperren. - Ein
PESSIMISTIC_WRITE
Die Sperranforderung schlägt fehl, wenn ein anderer Benutzer derzeit entweder einenPESSIMISTIC_WRITE
besitzt lock oder einPESSIMISTIC_READ
dieses Datenbankobjekt sperren.
Festlegen des Abfragehinweises (Bereiche)
Abfragehinweise können in den folgenden Bereichen festgelegt werden (von global bis lokal):
Für die gesamte Persistenzeinheit - unter Verwendung einer persistence.xml
Eigenschaft:
<properties>
<property name="javax.persistence.query.timeout" value="3000"/>
</properties>
Für eine EntityManagerFactory – mit createEntityManagerFacotory
Methode:
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 4000);
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("pu", properties);
Für einen EntityManager - mit dem createEntityManager
Methode:
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 5000);
EntityManager em = emf.createEntityManager(properties);
oder mit der setProperty-Methode:
em.setProperty("javax.persistence.query.timeout", 6000);
Für eine named query
Definition - mit den hints
Element:
@NamedQuery(name="Country.findAll", query="SELECT c FROM Country c",
hints={@QueryHint(name="javax.persistence.query.timeout", value="7000")})
Für eine bestimmte Abfrageausführung - mit setHint
Methode (vor der Abfrageausführung):
query.setHint("javax.persistence.query.timeout", 8000);