Mengubah data menggunakan operasi tulis batch

Halaman ini menjelaskan permintaan penulisan batch Spanner dan cara menggunakannya untuk mengubah data Spanner.

Anda dapat menggunakan batch write Spanner untuk menyisipkan, memperbarui, atau menghapus beberapa baris di tabel Spanner. Penulisan batch Spanner mendukung penulisan latensi rendah tanpa operasi baca, dan menampilkan respons saat mutasi diterapkan dalam batch. Untuk menggunakan batch write, Anda mengelompokkan mutasi terkait bersama-sama, dan semua mutasi dalam grup di-commit secara atomik. Mutasi pada seluruh kelompok diterapkan dalam urutan yang tidak ditentukan dan tidak bergantung satu sama lain (non-atomik). Spanner tidak perlu menunggu semua mutasi diterapkan sebelum mengirim respons, yang berarti bahwa operasi tulis dalam batch memungkinkan kegagalan sebagian. Anda juga dapat menjalankan beberapa batch operasi tulis sekaligus. Untuk mengetahui informasi selengkapnya, lihat Cara menggunakan batch write.

Kasus penggunaan

Penulisan batch Spanner sangat berguna jika Anda ingin melakukan commit dalam jumlah besar tanpa operasi baca, tetapi tidak memerlukan transaksi atomik untuk semua mutasi.

Jika Anda ingin mengelompokkan permintaan DML, gunakan batch DML untuk mengubah data Spanner Anda. Untuk mengetahui informasi lebih lanjut tentang perbedaan antara DML dan mutasi, baca Membandingkan DML dan mutasi.

Untuk permintaan mutasi tunggal, sebaiknya gunakan transaksi baca-tulis penguncian.

Batasan

Penulisan batch Spanner memiliki batasan berikut:

  • Batch write Spanner tidak tersedia menggunakan Google Cloud Console atau Google Cloud CLI. Ini hanya tersedia menggunakan REST dan RPC API serta library klien Java Spanner.

  • Perlindungan replay tidak didukung menggunakan batch operasi tulis. Mutasi dapat diterapkan lebih dari sekali, dan mutasi yang diterapkan lebih dari sekali dapat mengakibatkan kegagalan. Misalnya, jika mutasi insert direplay, hal tersebut mungkin menghasilkan error yang sudah ada, atau jika Anda menggunakan kunci berbasis stempel waktu yang dibuat atau di-commit dalam mutasi, hal tersebut dapat mengakibatkan baris tambahan ditambahkan ke tabel. Sebaiknya buat struktur penulisan Anda agar bersifat idempoten untuk menghindari masalah ini.

  • Anda tidak dapat melakukan rollback permintaan penulisan batch yang telah selesai. Anda dapat membatalkan permintaan penulisan batch yang sedang berlangsung. Jika Anda membatalkan penulisan batch yang sedang berlangsung, mutasi dalam grup yang belum selesai akan di-roll back. Mutasi dalam kelompok yang telah selesai dilakukan pada {i>database<i}.

  • Ukuran maksimum untuk permintaan batch operasi tulis sama dengan batas untuk permintaan commit. Untuk informasi selengkapnya, lihat Batas untuk membuat, membaca, memperbarui, dan menghapus data.

Cara menggunakan batch write

Untuk menggunakan batch write, Anda harus memiliki izin spanner.databases.write pada database yang ingin diubah. Anda dapat mengelompokkan mutasi secara non-atomik dalam satu panggilan menggunakan panggilan permintaan REST atau RPC API.

Anda harus mengelompokkan jenis mutasi berikut saat menggunakan batch write:

  • Menyisipkan baris dengan awalan kunci utama yang sama di tabel induk dan turunan.
  • Menyisipkan baris ke dalam tabel dengan hubungan kunci asing di antara tabel.
  • Jenis mutasi terkait lainnya bergantung pada skema database dan logika aplikasi Anda.

Anda juga dapat menulis batch menggunakan library klien Java Spanner. Contoh kode berikut memperbarui tabel Singers dengan baris baru.

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());
        }
      }
    }
  }
}

Langkah selanjutnya