web-dev-qa-db-fra.com

Comment spécifier un délai d'expiration @lock dans une requête jpa de données de printemps?

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é.

13
user2501759

Pour verrouiller les entités de façon pessimiste, définissez le mode de verrouillage sur PESSIMISTIC_READ, PESSIMISTIC_WRITE ou PESSIMISTIC_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 une LockTimeoutException 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:

  1. L'argument à l'un des EntityManager ou Query methods.
  2. Le paramètre dans l'annotation @NamedQuery.
  3. L'argument de la méthode Persistence.createEntityManagerFactory.
  4. La valeur dans le descripteur de déploiement persistence.xml.

Pour Spring Data 1.6 ou supérieur

@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.

D'autre part,

Pour la version précédente de Spring Data 1.6

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.

Lien de ressource:

  1. Comment activer LockModeType.PESSIMISTIC_WRITE lors de la recherche d'entités avec Spring Data JPA?
  2. Comment ajouter une méthode personnalisée à Spring Data JPA
  3. Expiration du délai de verrouillage pessimiste des données de printemps avec Postgres
  4. API de requête JPA

Divers exemple de délai d'attente de verrouillage pessimiste

Définir un verrou pessimiste

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é:

  • Une demande de verrouillage 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.
  • Une demande de verrouillage 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.

Définition d'un indice de requête (étendues)

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);

Lien de ressource:

  1. Verrouillage de JPA
  2. Délai de verrouillage pessimiste
15
SkyWalker

Vous pouvez utiliser @QueryHints in Spring Data:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
Stock findById(String id)
8
Dragan Bozanovic

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);
1
arpit garg