Java - JPA - @Version annotation


Comment fonctionne l'annotation @Version dans JPA?

J'ai trouvé diverses réponses dont l'extrait est le suivant:

JPA utilise un champ version dans vos entités pour détecter les modifications simultanées sur le même enregistrement de banque de données. Lorsque le runtime JPA détecte une tentative de modification simultanée du même enregistrement, il lève une exception à la transaction qui tente de valider en dernier.

Mais je ne sais toujours pas comment cela fonctionne.


Également à partir de ce qui suit lignes:

Vous devriez considérer les champs de version immuables. La modification de la valeur du champ a des résultats indéfinis.

Signifie que nous devons déclarer notre champ de version comme final?

Author: ROMANIA_engineer, 2010-04-04

5 answers

Mais je ne sais toujours pas comment cela fonctionne?

Disons qu'une entité MyEntity a une propriété annotée version:

@Entity
public class MyEntity implements Serializable {    

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Version
    private Long version;

    //...
}

Lors de la mise à jour, le champ annoté avec {[4] } sera incrémenté et ajouté à la clause WHERE, quelque chose comme ceci:

UPDATE MYENTITY SET ..., VERSION = VERSION + 1 WHERE ((ID = ?) AND (VERSION = ?))

Si la clause WHERE ne correspond pas à un enregistrement (car la même entité a déjà été mise à jour par un autre thread), le fournisseur de persistance lancera un OptimisticLockException.

Signifie que nous devrions déclarer notre champ version finale

Non, mais vous pouvez envisager de protéger le setter car vous n'êtes pas censé l'appeler.

 159
Author: Pascal Thivent, 2010-04-03 20:50:45

Bien que la réponse @ Pascal soit parfaitement valide, d'après mon expérience, je trouve le code ci-dessous utile pour accomplir un verrouillage optimiste:

@Entity
public class MyEntity implements Serializable {    
    // ...

    @Version
    @Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false)
    private long version = 0L;

    // ...
}

Pourquoi? Parce que:

  1. verrouillage Optimiste ne fonctionne pas si le champ annoté avec @Version est accidentellement mis à null.
  2. Comme ce champ spécial n'est pas nécessairement une version commerciale de l'objet, pour éviter une erreur, je préfère nommer ce champ à sth comme optlock plutôt que version.

Le premier point ne qu'importe si l'application utilise uniquement JPA pour insérer des données dans la base de données, car le fournisseur JPA appliquera 0 pour le champ @version au moment de la création. Mais presque toujours des instructions SQL simples sont également utilisées (au moins pendant les tests unitaires/ d'intégration).

 20
Author: G. Demecki, 2014-11-04 09:39:49

Chaque fois qu'une entité est mise à jour dans la base de données, le champ version est augmenté d'un. Chaque opération qui met à jour l'entité dans la base de données aura ajouté WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASE à sa requête.

En vérifiant les lignes affectées de votre opération, le framework jpa peut s'assurer qu'il n'y a pas eu de modification simultanée entre le chargement et la persistance de votre entité car la requête ne trouverait pas votre entité dans la base de données lorsque son numéro de version a été augmenté entre le chargement et la persistance.

 8
Author: stefanglase, 2010-04-03 20:50:09

Version utilisée pour garantir qu'une seule mise à jour à la fois. Le fournisseur JPA vérifiera la version, si la version attendue augmente déjà, alors quelqu'un d'autre met déjà à jour l'entité afin qu'une exception soit levée.

La mise à jour de la valeur de l'entité serait donc plus sûre, plus optimiste.

Si la valeur change fréquemment, vous pouvez envisager de ne pas utiliser le champ version. Pour un exemple "une entité qui a un champ de compteur, qui augmentera chaque fois qu'une page Web accédera"

 1
Author: uudashr, 2011-08-22 06:07:48

Il suffit d'ajouter un peu plus d'informations.

JPA gère la version sous le capot pour vous, mais il ne le fait pas lorsque vous mettez à jour votre enregistrement via JPAUpdateClause(), dans de tels cas, vous devez ajouter manuellement l'incrément de version à la requête.

Pedro

 1
Author: Pedro Borges, 2017-04-27 17:47:49