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_READlåsbegäran misslyckas om en annan användare (som representeras av en annan EntityManager-instans) för närvarande har enPESSIMISTIC_WRITElås på det databasobjektet. - En
PESSIMISTIC_WRITElåsbegäran misslyckas om en annan användare för närvarande har antingen enPESSIMISTIC_WRITElås eller enPESSIMISTIC_READlå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);