Agrega Spring Data Cloud Spanner a una aplicación

El módulo de Spring Data Cloud Spanner te permite usar Cloud Spanner en cualquier aplicación de Java compilada con el marco de trabajo Spring.

Como todos los módulos de Spring Data, Spring Data Cloud Spanner proporciona un modelo de programación basado en Spring que conserva las garantías de coherencia y escalabilidad de Cloud Spanner. Sus funciones son similares a Spring Data JPA y Hibernate ORM, con anotaciones diseñadas para Cloud Spanner.

Si ya estás familiarizado con Spring, entonces Spring Data Cloud Spanner puede facilitarte el trabajo con Cloud Spanner en tu aplicación y reducir la cantidad de código que debes escribir.

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

Instala el módulo

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

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-gcp-dependencies</artifactId>
      <version>1.2.5.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.springframework.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 esa cuenta para autenticarte con Google Cloud.

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

Configura el módulo

En esta sección, se describen algunas de las opciones de configuración más usadas para Spring Data Cloud Spanner. Si deseas obtener una lista completa de opciones de configuración, consulta la documentación de referencia.

Especifica una instancia y una base de datos

Debes especificar la base de datos y la instancia de Cloud Spanner a las que se conecta tu aplicación.

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

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

Modela datos de Cloud Spanner

Con Spring Data Cloud Spanner, puedes usar objetos antiguos planos de Java (POJO) para modelar los datos almacenados en tus tablas de Cloud Spanner.

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

Puedes usar las siguientes anotaciones para modelar relaciones simples entre entidades y tablas:

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

Opcional. Asigna la propiedad a una columna específica de la tabla de Cloud Spanner y anula la estrategia de nombres que asigna los nombres de manera automática.

Cuando omites esta propiedad, la estrategia de asignación de nombres predeterminada para Spring Data Cloud Spanner asigna los nombres de la propiedad camelCase de Java a los nombres de la columna PascalCase. Por ejemplo, se asigna la propiedad singerId al nombre de la columna SingerId.

@Embedded

Indica que la propiedad es un objeto incorporado que puede contener componentes de una clave primaria. Si la propiedad se usa realmente en la clave primaria, también debes incluir la anotación @PrimaryKey.

@Interleaved

@Interleaved(lazy = true)

Indica que una propiedad contiene una lista de filas que están intercaladas con la fila actual.

De forma predeterminada, Spring Data Cloud Spanner recupera las filas intercaladas durante la creación de la instancia. Para recuperar las filas de manera diferida, cuando accedas a la propiedad, usa @Interleaved(lazy = true).

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

@NotMapped

Indica que una propiedad no está almacenada en la base de datos y se debe ignorar.

@PrimaryKey

@PrimaryKey(keyOrder = N)

Indica que la propiedad es un componente de la clave primaria y, además, identifica la posición de la propiedad dentro de la clave primaria, a partir de 1. El valor predeterminado de 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 en la tabla. Reemplaza 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 Cloud Spanner para obtener detalles sobre otras anotaciones compatibles con el módulo.

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

  • Para las entidades de Singer, el ejemplo incluye una propiedad albums, con una anotación @Interleaved. Esta propiedad contiene una lista de álbumes que están intercalados con la entidad Singer. Spring Data Cloud Spanner propaga esta propiedad de forma automática.
  • Para las entidades de Album, en el ejemplo se incluye una propiedad relatedAlbums que no se almacena en Cloud Spanner.
import java.util.Date;
import java.util.List;
import org.springframework.cloud.gcp.data.spanner.core.mapping.Embedded;
import org.springframework.cloud.gcp.data.spanner.core.mapping.Interleaved;
import org.springframework.cloud.gcp.data.spanner.core.mapping.PrimaryKey;
import org.springframework.cloud.gcp.data.spanner.core.mapping.Table;

/**
 * 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 java.util.List;
import org.springframework.cloud.gcp.data.spanner.core.mapping.NotMapped;
import org.springframework.cloud.gcp.data.spanner.core.mapping.PrimaryKey;
import org.springframework.cloud.gcp.data.spanner.core.mapping.Table;

/**
 * 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;
  }
}

Consulta y modifica datos

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

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

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

Adquiere un bean de plantilla

Usa la anotación @Autowired para obtener un bean SpannerTemplate de forma automática. Luego, puedes 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 java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gcp.data.spanner.core.SpannerTemplate;
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"), null);
  }

}

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.

Adquiere un bean de repositorio

Si usas un SpannerRepository, puedes usar la anotación @Autowired para adquirir 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 java.util.List;
import org.springframework.cloud.gcp.data.spanner.repository.SpannerRepository;
import org.springframework.cloud.gcp.data.spanner.repository.query.Query;
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");
  }

}

Administra Cloud Spanner

Si deseas obtener información sobre tus bases de datos de Cloud Spanner, actualizar un esquema con una declaración de 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 de manera automática. Luego, puedes usar SpannerDatabaseAdminTemplate en toda la clase.

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gcp.data.spanner.core.admin.SpannerDatabaseAdminTemplate;
import org.springframework.cloud.gcp.data.spanner.core.admin.SpannerSchemaUtils;
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);
    }
  }
}

¿Qué sigue?