Modificare i dati utilizzando la scrittura in batch

Questa pagina descrive le richieste di scrittura batch di Spanner e come puoi utilizzare per modificare i tuoi dati Spanner.

Puoi utilizzare la scrittura batch di Spanner per inserire, aggiornare o eliminare più righe nelle tabelle Spanner. Spanner la scrittura batch supporta le scritture a bassa latenza senza un'operazione di lettura e restituisce e risposte così come le mutazioni vengono applicate in batch. Per utilizzare la scrittura in batch, raggruppa mutazioni correlate e tutte le mutazioni di un gruppo vengono commesse a livello atomico. Le mutazioni nei vari gruppi vengono applicate in un ordine non specificato e sono indipendenti l'uno dall'altro (non atomici). Spanner non ha bisogno attendere l'applicazione di tutte le mutazioni prima di inviare una risposta, il che significa la scrittura batch consente un errore parziale. Puoi anche eseguire più scrittura collettiva contemporaneamente. Per ulteriori informazioni, consulta la sezione Come utilizzare la scrittura batch.

Casi d'uso

La scrittura batch di Spanner è particolarmente utile se vuoi eseguire il commit di un gran numero di scritture senza un'operazione di lettura, ma non hai bisogno di una transazione atomica per tutte le mutazioni.

Se vuoi raggruppare le richieste DML, utilizza la DML batch per modificare i dati di Spanner. Per ulteriori informazioni sul differenze tra DML e mutazioni, consulta Confrontare DML e mutazioni.

Per le richieste di singole mutazioni, consigliamo di utilizzare una transazione di lettura/scrittura con blocco.

Limitazioni

La scrittura batch di Spanner presenta le seguenti limitazioni:

  • La scrittura batch di Spanner non è disponibile utilizzando la console Google Cloud o Google Cloud CLI. È disponibile solo utilizzando le API REST e RPC e la libreria client Java di Spanner.

  • La protezione da replay non è supportata con la scrittura batch. Le mutazioni possono essere applicata più di una volta e una mutazione applicata più di una volta potrebbe causare un errore. Ad esempio, se una mutazione di tipo insert viene riprodotta, potrebbe produrre un errore già esistente, oppure se si utilizza l'oggetto generato o di commit chiavi basate su timestamp nella mutazione, ciò potrebbe comportare la generazione di righe aggiuntive aggiunti alla tabella. Per evitare questo problema, ti consigliamo di strutturare le scritture in modo che siano idempotenti.

  • Non puoi eseguire il rollback di una richiesta di scrittura batch completata. Puoi annullare un richiesta di scrittura batch in corso. Se annulli una scrittura batch in corso, le mutazioni nei gruppi incompleti vengono annullate. Mutazioni nei gruppi completati nel database.

  • La dimensione massima per una richiesta di scrittura batch è uguale al limite per una richiesta di commit. Per ulteriori informazioni, vedi Limiti per la creazione, la lettura, l'aggiornamento e l'eliminazione dei dati.

Come utilizzare la scrittura in batch

Per utilizzare la scrittura in batch, devi disporre dell'autorizzazione spanner.databases.write al database che vuoi modificare. Puoi eseguire mutazioni collettive non atomiche in una singola chiamata utilizzando una chiamata di richiesta REST o API RPC.

Quando utilizzi la scrittura in batch, devi raggruppare i seguenti tipi di mutazione:

  • Inserire righe con lo stesso prefisso di chiave primaria sia nella rete principale che in quella secondaria tabelle.
  • Inserimento di righe nelle tabelle con una relazione di chiave esterna tra le tabelle.
  • Altri tipi di mutazioni correlate a seconda dello schema del database e della logica di applicazione.

Puoi anche eseguire scrittura collettiva utilizzando la libreria client Java di Spanner. Il codice di esempio seguente aggiorna la tabella Singers con nuove righe.

Java


import com.google.api.gax.rpc.ServerStream;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.MutationGroup;
import com.google.cloud.spanner.Options;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
import com.google.rpc.Code;
import com.google.spanner.v1.BatchWriteResponse;

public class BatchWriteAtLeastOnceSample {

  /***
   * Assume DDL for the underlying database:
   * <pre>{@code
   *   CREATE TABLE Singers (
   *     SingerId   INT64 NOT NULL,
   *     FirstName  STRING(1024),
   *     LastName   STRING(1024),
   *   ) PRIMARY KEY (SingerId)
   *
   *   CREATE TABLE Albums (
   *     SingerId     INT64 NOT NULL,
   *     AlbumId      INT64 NOT NULL,
   *     AlbumTitle   STRING(1024),
   *   ) PRIMARY KEY (SingerId, AlbumId),
   *   INTERLEAVE IN PARENT Singers ON DELETE CASCADE
   * }</pre>
   */

  private static final MutationGroup MUTATION_GROUP1 =
      MutationGroup.of(
          Mutation.newInsertOrUpdateBuilder("Singers")
              .set("SingerId")
              .to(16)
              .set("FirstName")
              .to("Scarlet")
              .set("LastName")
              .to("Terry")
              .build());
  private static final MutationGroup MUTATION_GROUP2 =
      MutationGroup.of(
          Mutation.newInsertOrUpdateBuilder("Singers")
              .set("SingerId")
              .to(17)
              .set("FirstName")
              .to("Marc")
              .build(),
          Mutation.newInsertOrUpdateBuilder("Singers")
              .set("SingerId")
              .to(18)
              .set("FirstName")
              .to("Catalina")
              .set("LastName")
              .to("Smith")
              .build(),
          Mutation.newInsertOrUpdateBuilder("Albums")
              .set("SingerId")
              .to(17)
              .set("AlbumId")
              .to(1)
              .set("AlbumTitle")
              .to("Total Junk")
              .build(),
          Mutation.newInsertOrUpdateBuilder("Albums")
              .set("SingerId")
              .to(18)
              .set("AlbumId")
              .to(2)
              .set("AlbumTitle")
              .to("Go, Go, Go")
              .build());

  static void batchWriteAtLeastOnce() {
    // TODO(developer): Replace these variables before running the sample.
    final String projectId = "my-project";
    final String instanceId = "my-instance";
    final String databaseId = "my-database";
    batchWriteAtLeastOnce(projectId, instanceId, databaseId);
  }

  static void batchWriteAtLeastOnce(String projectId, String instanceId, String databaseId) {
    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
      DatabaseId dbId = DatabaseId.of(projectId, instanceId, databaseId);
      final DatabaseClient dbClient = spanner.getDatabaseClient(dbId);

      // Creates and issues a BatchWrite RPC request that will apply the mutation groups
      // non-atomically and respond back with a stream of BatchWriteResponse.
      ServerStream<BatchWriteResponse> responses =
          dbClient.batchWriteAtLeastOnce(
              ImmutableList.of(MUTATION_GROUP1, MUTATION_GROUP2),
              Options.tag("batch-write-tag"));

      // Iterates through the results in the stream response and prints the MutationGroup indexes,
      // commit timestamp and status.
      for (BatchWriteResponse response : responses) {
        if (response.getStatus().getCode() == Code.OK_VALUE) {
          System.out.printf(
              "Mutation group indexes %s have been applied with commit timestamp %s",
              response.getIndexesList(), response.getCommitTimestamp());
        } else {
          System.out.printf(
              "Mutation group indexes %s could not be applied with error code %s and "
                  + "error message %s", response.getIndexesList(),
              Code.forNumber(response.getStatus().getCode()), response.getStatus().getMessage());
        }
      }
    }
  }
}

Passaggi successivi