

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Exemples de sémantique des transactions Neptune
<a name="transactions-examples"></a>

Les exemples suivants illustrent différents cas d'utilisation de la sémantique des transactions dans Amazon Neptune.

**Topics**
+ [Insertion conditionnelle d'une propriété](#transactions-examples-conditional-insertion)
+ [Unicité de valeur de propriété](#transactions-examples-unique-property)
+ [Modification de propriété conditionnelle](#transactions-examples-conditional-edit)
+ [Remplacement d'une propriété](#transactions-examples-replace)
+ [Éviter les éléments sans pendant](#transactions-examples-dangling)

## Exemple 1 : insertion d'une propriété uniquement si elle n'existe pas
<a name="transactions-examples-conditional-insertion"></a>

Supposons que vous souhaitiez vous assurer qu'une propriété ne sera définie qu'une seule fois. Par exemple, supposons que plusieurs requêtes tentent simultanément d'attribuer une cote de crédit à une personne. Vous souhaitez n'insérer qu'une seule instance de la propriété et que les autres requêtes échouent, car la propriété a déjà été définie.

```
# GREMLIN:
g.V('person1').hasLabel('Person').coalesce(has('creditScore'), property('creditScore', 'AAA+'))

# SPARQL:
INSERT { :person1 :creditScore "AAA+" .}
WHERE  { :person1 rdf:type :Person .
         FILTER NOT EXISTS { :person1 :creditScore ?o .} }
```

L'étape Gremlin `property()` insère une propriété avec la clé et la valeur données. L'étape `coalesce()` exécute le premier argument de la première étape, et si elle échoue, elle exécute la deuxième étape :

Avant d'insérer la valeur de la propriété `creditScore` pour un sommet `person1` donné, une transaction doit essayer de lire la valeur `creditScore` potentiellement inexistante pour `person1`. Cette tentative de lecture verrouille la plage `SP` pour `S=person1` et `P=creditScore` dans l'index `SPOG` où la valeur `creditScore` se trouve ou sera écrite.

Le fait d'effectuer ce verrouillage de plage empêche toute transaction simultanée d'insérer simultanément une valeur `creditScore`. Lorsqu'il y a plusieurs transactions parallèles, une seule d'entre elles peut mettre à jour la valeur à un moment donné. Cela exclut l'anomalie consistant en la création de plusieurs propriétés `creditScore`.

## Exemple 2 : assertion selon laquelle une valeur de propriété est globalement unique
<a name="transactions-examples-unique-property"></a>

Supposons que vous souhaitiez insérer une personne avec un numéro de sécurité sociale comme clé primaire. Vous souhaitez que votre requête de mutation garantisse que, au niveau global, personne d'autre dans la base de données n'a le même numéro de sécurité sociale :

```
# GREMLIN:
g.V().has('ssn', 123456789).fold()
  .coalesce(__.unfold(),
            __.addV('Person').property('name', 'John Doe').property('ssn', 123456789'))

# SPARQL:
INSERT { :person1 rdf:type :Person .
         :person1 :name "John Doe" .
         :person1 :ssn 123456789 .}
WHERE  { FILTER NOT EXISTS { ?person :ssn 123456789 } }
```

Cet exemple est similaire au précédent. La principale différence est que le verrouillage de plage est effectué sur l'index `POGS` au lieu de l'index `SPOG`.

La transaction qui exécute la requête doit lire le modèle, `?person :ssn 123456789`, dans lequel les positions `O` et `P` sont liées. Le verrouillage de plage est effectué sur l'index `POGS` pour `P=ssn` et `O=123456789`.
+ Si le modèle existe, aucune action n'est effectuée.
+ S'il n'existe pas, le verrouillage empêche toute transaction simultanée d'insérer également ce numéro de sécurité sociale.

## Exemple 3 : modification d'une propriété si une autre propriété a une valeur spécifiée
<a name="transactions-examples-conditional-edit"></a>

Supposons que divers événements d'un jeu déplacent une personne du niveau 1 au niveau 2 et lui attribue une nouvelle propriété `level2Score` définie sur zéro. Vous devez vous assurer que plusieurs instances simultanées de cette transaction ne puissent pas créer plusieurs instances de la propriété de score de niveau 2. Les requêtes dans Gremlin et SPARQL peuvent ressembler à ce qui suit.

```
# GREMLIN:
g.V('person1').hasLabel('Person').has('level', 1)
 .property('level2Score', 0)
 .property(Cardinality.single, 'level', 2)

# SPARQL:
DELETE { :person1 :level 1 .}
INSERT { :person1 :level2Score 0 .
         :person1 :level 2 .}
WHERE  { :person1 rdf:type :Person .
         :person1 :level 1 .}
```

Dans Gremlin, lorsque `Cardinality.single` est spécifié, l'étape `property()` ajoute une nouvelle propriété ou remplace une valeur de propriété existante par la nouvelle valeur spécifiée.

Toute mise à jour d'une valeur de propriété, telle que le passage de la valeur de `level` de 1 à 2, est implémentée sous la forme d'une suppression de l'enregistrement actuel et de l'insertion d'un nouvel enregistrement avec la nouvelle valeur de propriété. Dans ce cas, l'enregistrement avec le numéro de niveau 1 est supprimé et un enregistrement avec le numéro de niveau 2 est réinséré.

Pour que la transaction puisse ajouter `level2Score` et mettre à jour la valeur de `level` de 1 à 2, elle doit d'abord valider le fait que la valeur de `level` est actuellement égale à 1. Pour ce faire, elle effectue un verrouillage de plage sur le préfixe `SPO` pour `S=person1`, `P=level` et `O=1` dans l'index `SPOG`. Ce verrouillage empêche les transactions simultanées de supprimer le triplet de version 1. Par conséquent, aucune mise à jour simultanée conflictuelle ne peut se produire.

## Exemple 4 : remplacement d'une propriété existante
<a name="transactions-examples-replace"></a>

Certains événements peuvent mettre à jour la cote de crédit d'une personne en la remplaçant par une nouvelle valeur (ici, `BBB`). Mais vous voulez vous assurer que les événements simultanés de ce type ne puissent pas créer plusieurs propriétés de cote de crédit pour une personne.

```
# GREMLIN:
g.V('person1').hasLabel('Person')
 .sideEffect(properties('creditScore').drop())
 .property('creditScore', 'BBB')

# SPARQL:
DELETE { :person1 :creditScore ?o .}
INSERT { :person1 :creditScore "BBB" .}
WHERE  { :person1 rdf:type :Person .
         :person1 :creditScore ?o .}
```

Ce cas est similaire à l'exemple 3, sauf qu'au lieu de verrouiller le préfixe `SPO`, Neptune verrouille le préfixe `P=creditScore` avec `SP` et `S=person1` uniquement. Cela empêche les transactions simultanées d'insérer ou de supprimer des triplets avec la propriété `creditScore` pour le sujet `person1`.

## Exemple 5 : éviter les propriétés ou les arêtes sans pendant
<a name="transactions-examples-dangling"></a>

La mise à jour d'une entité ne doit pas laisser un élément sans pendant, c'est-à-dire une propriété ou un arc associé à une entité inexistante. Il s'agit uniquement d'un problème dans SPARQL, car Gremlin a des contraintes intégrées permettant d'empêcher l'existence d'éléments sans pendants.

```
# SPARQL:
tx1: INSERT { :person1 :age 23 } WHERE { :person1 rdf:type :Person }
tx2: DELETE { :person1 ?p ?o }
```

La requête `INSERT` doit lire et verrouiller le préfixe `SPO` avec `S=person1`, `P=rdf:type` et `O=Person` dans l'index `SPOG`. Le verrouillage empêche la requête `DELETE` de réussir en parallèle.

Dans la course entre la requête `DELETE` qui tente de supprimer l'enregistrement `:person1 rdf:type :Person` et la requête `INSERT` qui lit l'enregistrement et crée un verrouillage de plage sur son élément `SPO` dans l'index `SPOG`, les résultats possibles sont les suivants :
+ Si la requête `INSERT` est validée avant que la requête `DELETE` ne lise et supprime tous les enregistrements pour `:person1`, `:person1` est entièrement supprimé de la base de données, y compris l'enregistrement nouvellement inséré.
+ Si la requête `DELETE` est validée avant que la requête `INSERT` n'essaie de lire l'enregistrement `:person1 rdf:type :Person`, la lecture constate que la modification est validée. Autrement dit, elle ne trouve aucun enregistrement `:person1 rdf:type :Person` et devient donc un instruction non-opérationnelle.
+ Si la requête `INSERT` est lue avant la requête `DELETE`, le triplet `:person1 rdf:type :Person` est verrouillé et la requête `DELETE` est bloquée jusqu'à ce que la requête INSERT soit validée, comme dans le premier cas précédemment.
+ Si la requête `DELETE` est lue avant la requête `INSERT` et que la requête `INSERT` tente de lire et de verrouiller le préfixe `SPO` de l'enregistrement, un conflit est détecté. Cela est dû au fait que le triplet a été marqué pour suppression et que la requête `INSERT` a ensuite échoué.

Dans toutes ces différentes séquences d'événements possibles, aucun arc sans pendant n'est créé.