

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Ejemplos de semántica de transacciones de Neptune
<a name="transactions-examples"></a>

Los siguientes ejemplos muestran diferentes casos de uso de semántica de transacciones en Amazon Neptune.

**Topics**
+ [Inserción condicional de una propiedad](#transactions-examples-conditional-insertion)
+ [Unicidad del valor de la propiedad](#transactions-examples-unique-property)
+ [Cambio condicional de la propiedad](#transactions-examples-conditional-edit)
+ [Sustitución de una propiedad](#transactions-examples-replace)
+ [Evitar elementos pendientes](#transactions-examples-dangling)

## Ejemplo 1: inserción de una propiedad solo si no existe
<a name="transactions-examples-conditional-insertion"></a>

Supongamos que desea asegurarse de que una propiedad se establezca solo una vez. Por ejemplo, suponga que varias consultas intentan asignar a una persona una puntuación de crédito de forma simultánea. Solo desea que se inserte una instancia de la propiedad y que las demás consultas devuelvan un error, ya que la propiedad ya se ha establecido.

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

El el paso `property()` de Gremlin, se inserta una propiedad con la clave y el valor determinados. En el paso `coalesce()`, se ejecuta el primer argumento del primer paso y, si se produce un error, se ejecuta el segundo paso:

Antes de insertar el valor de la propiedad `creditScore` para un vértice `person1` determinado, una transacción debe intentar leer el posible valor `creditScore` inexistente de `person1`. Este intento de lectura bloquea el rango `SP` de `S=person1` y `P=creditScore` en el índice`SPOG`, donde el valor `creditScore` existe o se va a sobrescribir.

Si se utiliza este bloqueo de rango, se impide que cualquier transacción simultánea inserte un valor `creditScore` de forma simultánea. Cuando hay varias transacciones en paralelo, como máximo una de ellas puede actualizar el valor a la vez. Esto descarta la anomalía de más de una propiedad `creditScore` que se crea.

## Ejemplo 2: afirmación de que el valor de una propiedad es único de forma global
<a name="transactions-examples-unique-property"></a>

Supongamos que desea insertar una persona con un número de la Seguridad Social como clave principal. Desea que su consulta de mutación garantice que, a nivel global, nadie más de la base de datos tenga el mismo número de Seguridad Social:

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

Este ejemplo es similar al anterior. La principal diferencia es que el bloqueo de rango se realiza en el índice `POGS` en lugar de en el índice `SPOG`.

La transacción que ejecuta la consulta debe leer el patrón, `?person :ssn 123456789`, en el que están vinculadas las posiciones `P` y `O`. El bloqueo de rango se realiza en el índice `POGS` para `P=ssn` y `O=123456789`.
+ Si el patrón existe, no se realiza ninguna acción.
+ Si no existe, el bloqueo impide que cualquier transacción simultánea inserte también ese número de Seguridad Social.

## Ejemplo 3: cambio de una propiedad si otra propiedad tiene un valor específico
<a name="transactions-examples-conditional-edit"></a>

Supongamos que varios eventos de un juego mueven a una persona del nivel uno al nivel dos y les asignan una nueva propiedad `level2Score` establecida en cero. Debe asegurarse de que varias instancias simultáneas de dicha transacción no puedan crear varias instancias de la propiedad de puntuación de nivel dos. Las consultas en Gremlin y SPARQL podrían tener un aspecto similar al siguiente.

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

En Gremlin, cuando se especifica `Cardinality.single`, el paso `property()` añade una nueva propiedad o sustituye un valor de propiedad existente por el nuevo valor que se especifica.

Cualquier actualización de un valor de propiedad, como aumentar `level` de 1 a 2, se implementa como una eliminación del registro actual y la inserción de un nuevo registro con el nuevo valor de propiedad. En este caso, se elimina el registro con el número de nivel 1 y se vuelve a insertar un registro con el número de nivel 2.

Para que la transacción pueda añadir `level2Score` y actualizar `level` de 1 a 2, primero debe validar que el valor `level` sea actualmente igual a 1. Al hacerlo, toma un bloqueo de rango en el prefijo `SPO` de `S=person1`, `P=level` y `O=1` en el índice `SPOG`. Este bloqueo impide que las transacciones simultáneas eliminen el triple de la versión 1 y, como resultado, no se pueden producir actualizaciones simultáneas en conflicto.

## Ejemplo 4: sustitución de una propiedad existente
<a name="transactions-examples-replace"></a>

Algunos eventos pueden actualizar la puntuación de crédito de una persona a un nuevo valor (aquí `BBB`). Sin embargo, desea asegurarse de que los eventos simultáneos de ese tipo no puedan crear varias propiedades de puntuación de crédito para una persona.

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

Este caso es similar al ejemplo 3, salvo que en lugar de bloquear el prefijo `SPO`, Neptune bloquea el prefijo `SP` solo con `S=person1` y `P=creditScore`. Esto impide que las transacciones simultáneas inserten o eliminen triples con la propiedad `creditScore` para el asunto `person1`.

## Ejemplo 5: evitar propiedades o bordes pendientes
<a name="transactions-examples-dangling"></a>

La actualización de una entidad no debe dejar un elemento pendiente, es decir, una propiedad o borde asociado a una entidad que no esté escrita. Esto solo es un problema en SPARQL, ya que Gremlin tiene restricciones integradas para evitar elementos pendientes.

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

La consulta `INSERT` debe leer y bloquear el prefijo `SPO` con `S=person1`, `P=rdf:type` y `O=Person` en el índice `SPOG`. El bloqueo impide que la consulta `DELETE` se realice correctamente en paralelo.

En la carrera entre la consulta `DELETE` que intenta eliminar el registro `:person1 rdf:type :Person` y la consulta `INSERT` que lee el registro y crea un bloqueo de rango en su `SPO` en el índice `SPOG`, son posibles los siguientes resultados:
+ Si la consulta `INSERT` se confirma antes de que la consulta `DELETE` lea y elimine todos los registros de `:person1`, `:person1` se elimina en su totalidad de la base de datos, incluido el registro recién insertado.
+ Si la consulta `DELETE` se confirma antes de que la consulta `INSERT` intente leer el registro `:person1 rdf:type :Person`, la lectura observa el cambio confirmado. Es decir, no encuentra ningún registro `:person1 rdf:type :Person` y, por lo tanto, se convierte en una instrucción no-op (sin operación).
+ Si la consulta `INSERT` se lee antes que la consulta `DELETE`, el triple `:person1 rdf:type :Person` se bloquea y la consulta `DELETE` se bloquea hasta que se confirma la consulta INSERT, como en el primer caso anterior.
+ Si `DELETE` se lee antes que la consulta `INSERT` y la consulta `INSERT` intenta leer y bloquear el prefijo `SPO` del registro, se detecta un conflicto. Esto se debe a que el triple se ha marcado para su eliminación y, por lo tanto, se produce un fallo en `INSERT`.

En todas estas diferentes secuencias posibles de eventos, no se crea ningún borde pendiente.