För Spring Data 1.6 eller senare
@Lock
stöds på CRUD-metoder från och med version 1.6 av Spring Data JPA (det finns faktiskt redan en milstolpe
tillgängligt). Se denna biljett
för mer information.
Med den versionen deklarerar du helt enkelt följande:
interface WidgetRepository extends Repository<Widget, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Widget findOne(Long id);
}
Detta kommer att få CRUD-implementeringsdelen av backing repository proxy att tillämpa den konfigurerade LockModeType på find(…)
ring på EntityManager
.
Å andra sidan,
För tidigare version av Spring Data 1.6
Vårdata-pessimistiska @Lock
anteckningar gäller endast (som du påpekade) för frågor. Det finns inga anteckningar jag känner till som kan påverka en hel transaktion. Du kan antingen skapa en findByOnePessimistic
metod som anropar findByOne
med ett pessimistiskt lås eller så kan du ändra findByOne
att alltid få ett pessimistiskt lås.
Om du ville implementera din egen lösning så kunde du förmodligen. Under huven @Lock
anteckningen behandlas av LockModePopulatingMethodIntercceptor
som gör följande:
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
Du kan skapa någon statisk låshanterare som hade en ThreadLocal<LockMode>
medlemsvariabeln och sedan ha en aspekt lindad runt varje metod i varje arkiv som kallas bindResource med låsläget inställt i ThreadLocal. Detta skulle tillåta dig att ställa in låsläget per tråd. Du kan sedan skapa din egen @MethodLockMode
anteckning som skulle slå in metoden i en aspekt som ställer in det trådspecifika låsläget innan metoden körs och rensar den efter att metoden har körts.
Resurslänk:
- Hur aktiverar du LockModeType.PESSIMISTIC_WRITE när du letar upp enheter med Spring Data JPA?
- Så lägger du till anpassad metod för att Spring Data JPA
- Spring Data Pessimistic Lock timeout med Postgres
- JPA Query API
Olika exempel på pessimistisk låstid
Ställa in ett pessimistiskt lås
Ett entitetsobjekt kan låsas explicit med låsmetoden:
em.lock(employee, LockModeType.PESSIMISTIC_WRITE);
Det första argumentet är ett entitetsobjekt. Det andra argumentet är det begärda låsläget.
En TransactionRequiredException
kastas om det inte finns någon aktiv transaktion när låset anropas eftersom explicit låsning kräver en aktiv transaktion.
En LockTimeoutException
kastas om det begärda pessimistiska låset inte kan beviljas:
- En
PESSIMISTIC_READ
låsbegäran misslyckas om en annan användare (som representeras av en annan EntityManager-instans) för närvarande har enPESSIMISTIC_WRITE
lås på det databasobjektet. - En
PESSIMISTIC_WRITE
låsbegäran misslyckas om en annan användare för närvarande har antingen enPESSIMISTIC_WRITE
lås eller enPESSIMISTIC_READ
lås på databasobjektet.
Ställa in frågetips (omfång)
Frågetips kan ställas in i följande omfång (från globalt till lokalt):
För hela persistensenheten - med en persistence.xml
egenskap:
<properties>
<property name="javax.persistence.query.timeout" value="3000"/>
</properties>
För en EntityManagerFactory - med createEntityManagerFacotory
metod:
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 4000);
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("pu", properties);
För en EntityManager - med createEntityManager
metod:
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 5000);
EntityManager em = emf.createEntityManager(properties);
eller med metoden setProperty:
em.setProperty("javax.persistence.query.timeout", 6000);
För en named query
definition - med hjälp av hints
element:
@NamedQuery(name="Country.findAll", query="SELECT c FROM Country c",
hints={@QueryHint(name="javax.persistence.query.timeout", value="7000")})
För en specifik frågekörning - använd setHint
metod (innan fråga körs):
query.setHint("javax.persistence.query.timeout", 8000);