

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Beispiele für die Neptune-Transaktionssemantik
<a name="transactions-examples"></a>

Die folgenden Beispiele zeigen verschiedene Anwendungsfälle für die Transaktionssemantik in Amazon Neptune.

**Topics**
+ [Bedingtes Einfügen einer Eigenschaft](#transactions-examples-conditional-insertion)
+ [Eindeutigkeit eines Eigenschaftswerts](#transactions-examples-unique-property)
+ [Bedingte Eigenschaftsänderung](#transactions-examples-conditional-edit)
+ [Ersetzen einer Eigenschaft](#transactions-examples-replace)
+ [Vermeiden hängender Elemente](#transactions-examples-dangling)

## Beispiel 1 – Einfügen einer Eigenschaft nur in dem Fall, dass sie nicht vorhanden ist
<a name="transactions-examples-conditional-insertion"></a>

Angenommen, Sie möchten sicherstellen, dass eine Eigenschaft nur einmal angegeben wird. Nehmen Sie beispielsweise an, mehrere Abfragen versuchen, einer Person gleichzeitig eine Kreditbewertung zuzuweisen. Sie möchten nur eine Instance der Eigenschaft einfügen und die anderen Abfragen fehlschlagen lassen, da die Eigenschaft bereits festgelegt wurde.

```
# 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 .} }
```

Der Gremlin `property()`-Schritt fügt eine Eigenschaft mit dem angegebenen Schlüssel und Wert ein. Der `coalesce()`-Schritt führt das erste Argument im ersten Schritt aus, und wenn dies fehlschlägt, wird der zweite Schritt ausgeführt:

Bevor der Wert für die `creditScore`-Eigenschaft für einen bestimmten `person1`-Eckpunkt eingefügt wird, muss eine Transaktion versuchen, den möglicherweise nicht vorhandenen `creditScore`-Wert für `person1` zu lesen. Dieser versuchte Lesevorgang sperrt den `SP`- Bereich für `S=person1` und `P=creditScore` im `SPOG`-Index, in dem der `creditScore`-Wert entweder vorhanden ist oder geschrieben werden wird.

Durch diese Bereichssperre wird verhindert, dass gleichzeitige Transaktionen gleichzeitig einen `creditScore`- Wert einfügen. Wenn es mehrere parallele Transaktionen gibt, kann höchstens eine von ihnen den Wert zu einem bestimmten Zeitpunkt aktualisieren. Dies schließt die Anomalie der Erstellung mehr als einer `creditScore`-Eigenschaft aus.

## Beispiel 2 – Feststellung, dass ein Eigenschaftswert global eindeutig ist
<a name="transactions-examples-unique-property"></a>

Angenommen, Sie möchten eine Person mit einer Sozialversicherungsnummer als Primärschlüssel einfügen. Sie möchten, dass Ihre Mutationsabfrage sicherstellt, dass auf globaler Ebene niemand sonst in der Datenbank dieselbe Sozialversicherungsnummer hat:

```
# 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 } }
```

Dieses Beispiel ähnelt dem vorherigen. Der Hauptunterschied besteht darin, dass die Bereichssperre für den `POGS`-Index und nicht für den `SPOG`-Index gesetzt wird.

Die Transaktion, die die Abfrage ausführt, muss das Muster, `?person :ssn 123456789`, lesen, in dem die Positionen `P` und `O` gebunden sind. Die Bereichssperre wird für den `POGS`-Index für `P=ssn` und `O=123456789` gesetzt.
+ Wenn das Muster vorhanden ist, wird keine Aktion ausgeführt.
+ Wenn es nicht vorhanden ist, verhindert die Sperre, dass gleichzeitige Transaktionen auch diese Sozialversicherungsnummer einfügen.

## Beispiel 3 – Ändern einer Eigenschaft, wenn eine andere Eigenschaft einen bestimmten Wert hat
<a name="transactions-examples-conditional-edit"></a>

Nehmen wir an, dass verschiedene Ereignisse in einem Spiel eine Person von Level 1 auf Level 2 verschieben und ihr eine neue `level2Score`-Eigenschaft zuweisen, die auf Null gesetzt ist. Sie müssen sicherstellen, dass nicht mehrere gleichzeitige Instances einer solchen Transaktion mehrere Instances der Score-Eigenschaft von Level 2 erstellen können. Die Abfragen in Gremlin und SPARQL können wie folgt aussehen.

```
# 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 .}
```

Wenn in Gremlin `Cardinality.single` angegeben ist, fügt der `property()`- Schritt entweder eine neue Eigenschaft hinzu oder ersetzt einen vorhandenen Eigenschaftswert durch den neuen angegebenen Wert.

Jede Aktualisierung eines Eigenschaftswerts, z. B. das Erhöhen `level` von 1 auf 2, wird als Löschung des aktuellen Datensatzes und Einfügen eines neuen Datensatzes mit dem neuen Eigenschaftswert implementiert. In diesem Fall wird der Datensatz für Level 1 gelöscht, und ein Datensatz für Level 2 wird neu gesetzt.

Damit die Transaktion `level2Score` hinzufügen und `level` von 1 auf 2 aktualisieren kann, muss sie zunächst überprüfen, ob der `level`-Wert derzeit gleich 1 ist. Dafür wird eine Bereichssperre für das `SPO`-Präfix für `S=person1`, `P=level`, und `O=1` im `SPOG`-Index gesetzt. Diese Sperre verhindert, dass gleichzeitige Transaktionen das Version 1-Tripel löschen. Daher können keine widersprüchlichen gleichzeitigen Aktualisierungen stattfinden.

## Beispiel 4 – Ersetzen einer vorhandenen Eigenschaft
<a name="transactions-examples-replace"></a>

Bestimmte Ereignisse können die Kreditbewertungen einer Person auf einen neuen Wert aktualisieren (hier `BBB`). Sie möchten jedoch sicherstellen, dass gleichzeitige Ereignisse dieses Typs nicht mehrere Kreditbewertungseigenschaften für eine Person erstellen können.

```
# 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 .}
```

Dieser Fall ist Beispiel 3 ähnlich, mit der Ausnahme, dass Neptune nicht das `SPO`-Präfixe sperrt, sondern das Präfix `SP` nur bei `S=person1` und `P=creditScore` sperrt. Dadurch wird verhindert, dass gleichzeitige Transaktionen Tripel mit der `creditScore`-Eigenschaft für das `person1`-Subjekt einfügen oder löschen.

## Beispiel 5 – Vermeiden hängender Eigenschaften oder Kanten
<a name="transactions-examples-dangling"></a>

Die Aktualisierung einer Entität sollte kein hängendes Element zurücklassen, d. h. eine Eigenschaft oder Grenze, die einer nicht typisierten Entität zugeordnet ist. Dies ist nur ein Problem in SPARQL, da Gremlin über integrierte Einschränkungen verfügt, die hängende Elemente verhindern.

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

Die `INSERT`-Abfrage muss das `SPO`-Präfix mit `S=person1`, `P=rdf:type` und `O=Person` im `SPOG`-Index lesen und sperren. Diese Sperre verhindert, dass die `DELETE`-Abfrage parallel erfolgreich ist.

Beim „Rennen“ zwischen dem Versuch der `DELETE`- Abfrage, den `:person1 rdf:type :Person`-Datensatz zu löschen, und dem der `INSERT`-Abfrage, den Datensatz zu lesen und eine Bereichssperre für ihren `SPO` im `SPOG`-Index zu setzen, sind die folgenden Ergebnisse möglich:
+ Wenn die `INSERT`-Abfrage ein Commit durchführt, bevor die `DELETE`-Abfrage alle Datensätze für `:person1` liest und löscht, wird `:person1` vollständig aus der Datenbank entfernt, einschließlich des neu eingefügten Datensatzes.
+ Wenn die `DELETE`-Abfrage ein Commit durchführt, bevor die `INSERT`-Abfrage versucht, den `:person1 rdf:type :Person`-Datensatz zu lesen, beachtet der Lesevorgang die festgeschriebene Änderung. Das heißt, er findet keinen `:person1 rdf:type :Person`-Datensatz und wird daher nicht aktiv („No-op“).
+ Wenn die `INSERT`-Abfrage liest, bevor die `DELETE`-Abfrage dies tut, wird das `:person1 rdf:type :Person`-Tripel gesperrt, und die `DELETE`- Abfrage wird blockiert, bis die INSERT-Abfrage ein Commit durchführt, wie im ersten Fall zuvor.
+ Wenn `DELETE` vor der `INSERT`-Abfrage liest und die `INSERT`-Abfrage versucht, zu lesen und eine Sperre auf das `SPO`-Präfix für den Datensatz zu setzen, wird ein Konflikt erkannt. Der Grund hierfür ist, dass das Tripel zum Entfernen markiert wurde und der `INSERT` dann fehlschlägt.

Alle diese verschiedenen möglichen Ereignissequenzen führen nicht zum Erstellen hängender Grenzen.