Integrar Spanner con Spring Data

El módulo Spring Data Spanner te ayuda a usar Spanner en cualquier aplicación Java creada con Spring Framework.

Al igual que todos los módulos de Spring Data, Spring Data Spanner proporciona un modelo de programación basado en Spring que mantiene las garantías de coherencia y la escalabilidad de Spanner. Sus funciones son similares a las de Spring Data JPA y Hibernate ORM, con anotaciones diseñadas para Spanner. Para obtener más información sobre cómo usar Spring Data JPA con Spanner, consulta Integrar Spanner con Spring Data JPA (dialecto de GoogleSQL).

Si ya conoces Spring, Spring Data Spanner puede facilitarte el trabajo con Spanner en tu aplicación y reducir la cantidad de código que tienes que escribir.

En esta página se explica cómo añadir Spring Data Spanner a una aplicación Java. Para obtener información detallada sobre el módulo, consulta la referencia de Spring Data Spanner.

Instalar el módulo

Si usas Maven, añade la lista de materiales (BOM) de Spring Cloud GCP y Spring Data Spanner a tu archivo pom.xml. Estas dependencias proporcionan los componentes de Spring Data Spanner a tu Spring ApplicationContext:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>spring-cloud-gcp-dependencies</artifactId>
      <version>3.7.7</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>${spring.boot.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-data-spanner</artifactId>
  </dependency>
</dependencies>

También debes crear una cuenta de servicio y usar la clave de la cuenta de servicio para autenticarte en Google Cloud.

Para obtener más información, consulta las instrucciones para configurar un entorno de desarrollo de Java. No es necesario que instales la Google Cloud biblioteca de cliente de Java, ya que el starter de Spring Boot la instala automáticamente.

Configurar el módulo

En esta sección se describen algunos de los ajustes de configuración más habituales de Spring Data Spanner. Para ver una lista completa de los ajustes, consulta la documentación de referencia.

Especificar una instancia y una base de datos

Para especificar la instancia y la base de datos predeterminadas, define las siguientes propiedades de configuración de tu aplicación:

Propiedad Descripción
spring.cloud.gcp.spanner.project-id Opcional. El Google Cloud ID del proyecto. Sustituye el valor de spring.cloud.gcp.config.project-id.
spring.cloud.gcp.spanner.instance-id El ID de la instancia de Spanner.
spring.cloud.gcp.spanner.database La base de datos a la que se va a conectar.

Modelar datos de Spanner

Con Spring Data Spanner, puede usar objetos Java antiguos (POJOs) para modelar los datos que almacena en sus tablas de Spanner.

Por cada tabla de tu base de datos, declara una entidad que represente un registro de esa tabla. Usa anotaciones para asignar la entidad y sus propiedades a una tabla y a sus columnas.

Puedes usar las siguientes anotaciones para modelizar relaciones sencillas entre entidades y tablas:

Anotaciones de entidades
@Column(name = "columnName")

Opcional. Asigna la propiedad a una columna específica de la tabla de Spanner, lo que anula la estrategia de nomenclatura que asigna los nombres automáticamente.

Si omite esta propiedad, la estrategia de nomenclatura predeterminada de Spring Data Spanner asignará los nombres de las propiedades de Java camelCase a los nombres de las columnas PascalCase. Por ejemplo, la propiedad singerId se asigna al nombre de columna SingerId.

@Embedded

Indica que la propiedad es un objeto insertado que puede contener componentes de una clave principal. Si la propiedad se usa en la clave principal, también debe incluir la anotación @PrimaryKey.

@Interleaved

@Interleaved(lazy = true)

Indica que una propiedad contiene una lista de filas entrelazadas con la fila actual.

De forma predeterminada, Spring Data Spanner obtiene las filas intercaladas al crear la instancia. Para obtener las filas de forma diferida, cuando accedas a la propiedad, usa @Interleaved(lazy = true).

Ejemplo: Si una entidad Singer puede tener entradas Album intercaladas como elementos secundarios, añade una propiedad List<Album> a la entidad Singer. Además, añada una anotación @Interleaved a la propiedad.

@NotMapped

Indica que una propiedad no se almacena en la base de datos y debe ignorarse.

@PrimaryKey

@PrimaryKey(keyOrder = N)

Indica que la propiedad es un componente de la clave principal e identifica la posición de la propiedad en la clave principal, empezando por 1. El valor predeterminado keyOrder es 1.

Ejemplo: @PrimaryKey(keyOrder = 3)

@Table(name = "TABLE_NAME")

La tabla que modela la entidad. Cada instancia de la entidad representa un registro de la tabla. Sustituye TABLE_NAME por el nombre de tu tabla.

Ejemplo: @Table(name = "Singers")

Si necesitas modelar relaciones más complejas, consulta la referencia de Spring Data Spanner para obtener información sobre otras anotaciones que admite el módulo.

En los siguientes ejemplos se muestra una forma de modelar las tablas Singers y Albums para Spring Data Spanner:

  • En el caso de las entidades Singer, el ejemplo incluye una propiedad albums con una anotación @Interleaved. Esta propiedad contiene una lista de álbumes que se entrelazan con la entidad Singer. Spring Data Spanner rellena esta propiedad automáticamente.
  • En el caso de las entidades Album, el ejemplo incluye una propiedad relatedAlbums que no se almacena en Spanner.
import com.google.cloud.spring.data.spanner.core.mapping.Interleaved;
import com.google.cloud.spring.data.spanner.core.mapping.PrimaryKey;
import com.google.cloud.spring.data.spanner.core.mapping.Table;
import java.util.Date;
import java.util.List;


/**
 * An entity and table holding singers.
 */
@Table(name = "Singers")
public class Singer {
  @PrimaryKey
  long singerId;

  String firstName;

  String lastName;

  Date birthDate;

  @Interleaved
  List<Album> albums;
}
import com.google.cloud.spring.data.spanner.core.mapping.NotMapped;
import com.google.cloud.spring.data.spanner.core.mapping.PrimaryKey;
import com.google.cloud.spring.data.spanner.core.mapping.Table;
import java.util.List;

/**
 * An entity class representing an Album.
 */
@Table(name = "Albums")
public class Album {

  @PrimaryKey
  long singerId;

  @PrimaryKey(keyOrder = 2)
  long albumId;

  String albumTitle;

  long marketingBudget;

  @NotMapped
  List<Album> relatedAlbums;

  public Album(long singerId, long albumId, String albumTitle, long marketingBudget) {
    this.singerId = singerId;
    this.albumId = albumId;
    this.albumTitle = albumTitle;
    this.marketingBudget = marketingBudget;
  }
}

Consultar y modificar datos

Para consultar y modificar datos con Spring Data Spanner, puedes obtener un bean SpannerTemplate, que implementa SpannerOperations. SpannerTemplate proporciona métodos para realizar consultas SQL y modificar datos con instrucciones del lenguaje de manipulación de datos (DML). También puedes usar este bean para acceder a la API de lectura y a la API de mutación de Spanner.

Además, puedes ampliar la interfaz SpannerRepository para encapsular toda la lógica de la aplicación que consulta y modifica datos en Spanner.

En las siguientes secciones se explica cómo trabajar con SpannerTemplate y SpannerRepository.

Adquirir un bean de plantilla

Usa la anotación @Autowired para adquirir un bean SpannerTemplate automáticamente. Después, podrás usar SpannerTemplate en toda la clase.

En el siguiente ejemplo se muestra una clase que adquiere y usa el bean:

import com.google.cloud.spanner.KeySet;
import com.google.cloud.spanner.Statement;
import com.google.cloud.spring.data.spanner.core.SpannerQueryOptions;
import com.google.cloud.spring.data.spanner.core.SpannerTemplate;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * A quick start code for Spring Data Cloud Spanner. It demonstrates how to use SpannerTemplate to
 * execute DML and SQL queries, save POJOs, and read entities.
 */
@Component
public class SpannerTemplateSample {

  @Autowired
  SpannerTemplate spannerTemplate;

  public void runTemplateExample(Singer singer) {
    // Delete all of the rows in the Singer table.
    this.spannerTemplate.delete(Singer.class, KeySet.all());

    // Insert a singer into the Singers table.
    this.spannerTemplate.insert(singer);

    // Read all of the singers in the Singers table.
    List<Singer> allSingers = this.spannerTemplate
        .query(Singer.class, Statement.of("SELECT * FROM Singers"),
                new SpannerQueryOptions().setAllowPartialRead(true));
  }

}

Puedes usar el bean SpannerTemplate para ejecutar transacciones de solo lectura y transacciones de lectura y escritura. Además, puedes usar la anotación @Transactional para crear transacciones declarativas.

Adquirir un bean de repositorio

Si usas un SpannerRepository, puedes usar la anotación @Autowired para obtener un bean que implemente la interfaz de tu repositorio. Un repositorio incluye métodos para ejecutar funciones de Java como transacciones de solo lectura y transacciones de lectura y escritura. Para operaciones de nivel inferior, puedes obtener el bean de plantilla que usa el repositorio.

En los siguientes ejemplos se muestra la interfaz de un repositorio y una clase que adquiere y usa el bean:

import com.google.cloud.spanner.Key;
import com.google.cloud.spring.data.spanner.repository.SpannerRepository;
import com.google.cloud.spring.data.spanner.repository.query.Query;
import java.util.List;
import org.springframework.data.repository.query.Param;


/**
 * An interface of various Query Methods. The behavior of the queries is defined only by
 * their names, arguments, or annotated SQL strings. The implementation of these functions
 * is generated by Spring Data Cloud Spanner.
 */
public interface SingerRepository extends SpannerRepository<Singer, Key> {
  List<Singer> findByLastName(String lastName);

  int countByFirstName(String firstName);

  int deleteByLastName(String lastName);

  List<Singer> findTop3DistinctByFirstNameAndSingerIdIgnoreCaseOrLastNameOrderByLastNameDesc(
      String firstName, String lastName, long singerId);

  @Query("SELECT * FROM Singers WHERE firstName LIKE '%@fragment';")
  List<Singer> getByQuery(@Param("fragment") String firstNameFragment);
}
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * A quick start code for Spring Data Cloud Spanner.
 * It demonstrates how to use a SpannerRepository to execute read-write queries
 * generated from interface definitions.
 *
 */
@Component
public class SpannerRepositorySample {

  @Autowired
  SingerRepository singerRepository;

  public void runRepositoryExample() {
    List<Singer> lastNameSingers = this.singerRepository.findByLastName("a last name");

    int fistNameCount = this.singerRepository.countByFirstName("a first name");

    int deletedLastNameCount = this.singerRepository.deleteByLastName("a last name");
  }

}

Gestionar Spanner

Para obtener información sobre tus bases de datos de Spanner, actualizar un esquema con una instrucción del lenguaje de definición de datos (DDL) o completar otras tareas administrativas, puedes adquirir un bean SpannerDatabaseAdminTemplate.

Usa la anotación @Autowired para adquirir el bean automáticamente. Después, puedes usar la SpannerDatabaseAdminTemplate en toda la clase.

En el siguiente ejemplo se muestra una clase que adquiere y usa el bean:

import com.google.cloud.spring.data.spanner.core.admin.SpannerDatabaseAdminTemplate;
import com.google.cloud.spring.data.spanner.core.admin.SpannerSchemaUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * This sample demonstrates how to generate schemas for interleaved tables from POJOs and how to
 * execute DDL.
 */
@Component
public class SpannerSchemaToolsSample {

  @Autowired
  SpannerDatabaseAdminTemplate spannerDatabaseAdminTemplate;

  @Autowired
  SpannerSchemaUtils spannerSchemaUtils;

  /**
   * Creates the Singers table. Also creates the Albums table, because Albums is interleaved with
   * Singers.
   */
  public void createTableIfNotExists() {
    if (!this.spannerDatabaseAdminTemplate.tableExists("Singers")) {
      this.spannerDatabaseAdminTemplate.executeDdlStrings(
          this.spannerSchemaUtils
              .getCreateTableDdlStringsForInterleavedHierarchy(Singer.class),
          true);
    }
  }

  /**
   * Drops both the Singers and Albums tables using just a reference to the Singer entity type ,
   * because they are interleaved.
   */
  public void dropTables() {
    if (this.spannerDatabaseAdminTemplate.tableExists("Singers")) {
      this.spannerDatabaseAdminTemplate.executeDdlStrings(
          this.spannerSchemaUtils.getDropTableDdlStringsForInterleavedHierarchy(Singer.class),
          false);
    }
  }
}

Siguientes pasos