Comment spécifier @lock
timeout pour la requête. J'utilise Oracle 11g, j'espère pouvoir utiliser quelque chose comme 'select id from table where id = ?1 for update wait 5'
.
J'ai défini la méthode comme ça,
@Lock(LockModeType.PESSIMISTIC_WRITE)
Stock findById(String id);
il semble verrouiller pour toujours. J'ai mis javax.persistence.lock.timeout=0
dans LocalContainerEntityManagerFactoryBean.jpaProperties
, mais pas effectué.
Pour verrouiller les entités de façon pessimiste, définissez le mode de verrouillage sur
PESSIMISTIC_READ
,PESSIMISTIC_WRITE
ouPESSIMISTIC_FORCE_INCREMENT
.Si un verrou pessimiste ne peut pas être obtenu, mais que l’échec du verrouillage N’entraîne pas d’annulation de la transaction, une
LockTimeoutException
est renvoyée.Délais de verrouillage pessimistes
Le délai, en millisecondes, pendant lequel le fournisseur de persistance doit attendre Pour obtenir un verrou sur les tables de la base de données peut être spécifié à l'aide de , De la propriété javax.persistence.lock.timeout. Si le temps nécessaire pour Obtenir un verrou dépasse la valeur de cette propriété, un
LockTimeoutException
sera lancé, mais la transaction en cours Ne sera pas marquée pour être annulée. Si cette propriété est définie sur 0, le fournisseur De persistance doit émettre uneLockTimeoutException
s'il ne peut pas immédiatement obtenir un verrou.Si
javax.persistence.lock.timeout
est défini à plusieurs endroits, la valeur Sera déterminée dans l'ordre suivant:
- L'argument à l'un des
EntityManager
ouQuery methods
.- Le paramètre dans l'annotation
@NamedQuery
.- L'argument de la méthode
Persistence.createEntityManagerFactory
.- La valeur dans le descripteur de déploiement
persistence.xml
.
@Lock
est pris en charge sur les méthodes CRUD à partir de la version 1.6 de Spring Data JPA (en fait, il existe déjà un milestone disponible). Voir ce ticket pour plus de détails.
Avec cette version, vous déclarez simplement ce qui suit:
interface WidgetRepository extends Repository<Widget, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Widget findOne(Long id);
}
La partie mise en œuvre CRUD du proxy du référentiel de sauvegarde appliquera donc le LockModeType configuré à l'appel find(…)
sur la EntityManager
.
Les annotations pessimistes @Lock
de Spring Data s’appliquent uniquement (comme vous l’avez indiqué) aux requêtes. À ma connaissance, il n’existe pas d’annotations susceptibles d’affecter une transaction complète. Vous pouvez créer une méthode findByOnePessimistic
qui appelle findByOne
avec un verrou pessimiste ou vous pouvez modifier findByOne
pour toujours obtenir un verrou pessimiste.
Si vous vouliez implémenter votre propre solution, vous le pourriez probablement. Sous le capot, l'annotation @Lock
est traitée par LockModePopulatingMethodIntercceptor
qui effectue les opérations suivantes:
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
Vous pouvez créer un gestionnaire de verrous statiques comportant une variable membre ThreadLocal<LockMode>
, puis insérer un aspect dans chaque méthode de chaque référentiel appelé bindResource avec le mode de verrouillage défini dans le ThreadLocal. Cela vous permettrait de définir le mode de verrouillage par thread. Vous pouvez ensuite créer votre propre annotation @MethodLockMode
qui engloberait la méthode dans un aspect qui définit le mode de verrouillage spécifique au thread avant d'exécuter la méthode et l'efface après l'exécution de la méthode.
Un objet entité peut être verrouillé explicitement par la méthode lock:
em.lock(employee, LockModeType.PESSIMISTIC_WRITE);
Le premier argument est un objet entité. Le deuxième argument est le mode de verrouillage demandé.
Une TransactionRequiredException
est levée s'il n'y a pas de transaction active lorsque lock est appelé, car le verrouillage explicite nécessite une transaction active.
Un LockTimeoutException
est lancé si le verrou pessimiste demandé ne peut pas être accordé:
PESSIMISTIC_READ
échoue si un autre utilisateur (qui est Représenté par une autre instance de EntityManager) détient actuellement un verrou PESSIMISTIC_WRITE
sur cet objet de base de données.PESSIMISTIC_WRITE
échoue si un autre utilisateur Détient actuellement un verrou PESSIMISTIC_WRITE
ou un verrou PESSIMISTIC_READ
sur Cet objet de base de données.Les indicateurs de requête peuvent être définis dans les étendues suivantes (du global au local):
Pour l'unité de persistance entière - en utilisant une propriété persistence.xml
:
<properties>
<property name="javax.persistence.query.timeout" value="3000"/>
</properties>
Pour un EntityManagerFactory - en utilisant la méthode createEntityManagerFacotory
:
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 4000);
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("pu", properties);
Pour un EntityManager - en utilisant la méthode createEntityManager
:
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 5000);
EntityManager em = emf.createEntityManager(properties);
ou en utilisant la méthode setProperty:
em.setProperty("javax.persistence.query.timeout", 6000);
Pour une définition named query
- en utilisant l'élément hints
:
@NamedQuery(name="Country.findAll", query="SELECT c FROM Country c",
hints={@QueryHint(name="javax.persistence.query.timeout", value="7000")})
Pour une exécution de requête spécifique - en utilisant la méthode setHint
(avant l'exécution de la requête):
query.setHint("javax.persistence.query.timeout", 8000);
Vous pouvez utiliser @QueryHints
in Spring Data:
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
Stock findById(String id)
Pour Spring Data 1.6 ou supérieur, nous pouvons utiliser l'annotation @Lock fournie par Spring Data jpa.
En outre, le délai d'expiration du verrouillage peut également être défini à l'aide de @QueryHints. À l'origine, les annotations d'indication de requête n'étaient pas prises en charge dans les méthodes CRUD par défaut, mais elles étaient disponibles après le correctif 1.6M1. https://jira.spring.io/browse/DATAJPA-173
Vous trouverez ci-dessous un exemple de verrou pessimiste avec le type de mode PESSIMISTIC_WRITE qui est un verrou exclusif.
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
Customer findByCustomerId(Long customerId);