web-dev-qa-db-fra.com

Java - JPA - Annotation @Version

Comment fonctionne @Version annotations dans JPA?

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

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

Mais je ne sais toujours pas comment cela fonctionne.


Aussi à partir des lignes suivantes:

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

Cela signifie-t-il que nous devrions déclarer notre champ de version comme final?

107
Yatendra Goel

Mais je ne suis toujours pas sûr de savoir comment cela fonctionne?

Supposons qu'une entité MyEntity possède 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 @Version sera incrémenté et ajouté à la clause WHERE, 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 jette un OptimisticLockException.

Cela signifie-t-il que nous devrions déclarer notre champ de version comme définitif?

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

177
Pascal Thivent

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

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

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

    // ...
}

Pourquoi? Car:

  1. Verrouillage optimiste ne fonctionnera pas si le champ annoté avec @Version Est accidentellement défini sur null.
  2. Comme ce champ spécial n'est pas nécessairement une version commerciale de l'objet, pour éviter toute confusion, je préfère nommer ce champ comme tel optlock plutôt que version.

Le premier point importe peu si l'application utilise niquement JPA pour insérer des données dans la base de données, car le fournisseur JPA appliquera le champ 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).

26
G. Demecki

Chaque fois qu'une entité est mise à jour dans la base de données, le champ de version est augmenté d'un. Chaque opération mettant à 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, la structure 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 si son numéro de version a été augmenté entre le chargement et la persistance.

9
stefanglase

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à, une autre personne mettra déjà à jour l'entité et une exception sera levée.

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

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

2
uudashr

Juste en ajoutant un peu plus d'informations.

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

Pedro

0
Pedro Borges