Intégrer Spanner à Spring Data

Le module Spring Data Spanner vous aide à utiliser Spanner dans n'importe quelle application Java créée avec le framework Spring.

Comme tous les modules Spring Data, Spring Data Spanner fournit un modèle de programmation basé sur Spring qui conserve les garanties de cohérence et l'évolutivité de Spanner. Ses fonctionnalités sont semblables à celles de Spring Data JPA et Hibernate ORM, avec des annotations conçues pour Spanner. Pour en savoir plus sur l'utilisation de Spring Data JPA avec Spanner, consultez la page Intégrer Spanner avec Spring Data JPA (dialecte GoogleSQL).

Si vous connaissez déjà Spring, Spring Data Spanner peut faciliter l'utilisation de Spanner dans votre application et réduire la quantité de code à écrire.

Cette page explique comment ajouter Spring Data Spanner à une application Java. Pour en savoir plus sur le module, consultez la documentation de référence sur Spring Data Spanner.

Installer le module

Si vous utilisez Maven, ajoutez la nomenclature (BOM) GCP Spring Cloud et Spring Data Spanner à votre fichier pom.xml. Ces dépendances fournissent les composants Spring Data Spanner à votre ApplicationContext Spring:

<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>

Vous devez également créer un compte de service et utiliser la clé de compte de service pour vous authentifier avec Google Cloud.

Pour plus d'informations, consultez les instructions sur la configuration d'un environnement de développement Java. Vous n'avez pas besoin d'installer la bibliothèque cliente Google Cloud pour Java, Spring Boot s'en charge automatiquement au démarrage.

Configurer le module

Cette section décrit certains des paramètres de configuration les plus couramment utilisés pour Spring Data Spanner. Pour obtenir la liste complète des paramètres, consultez la documentation de référence.

Spécifier une instance et une base de données

Pour spécifier l'instance et la base de données par défaut, définissez les propriétés de configuration suivantes pour votre application :

Propriété Description
spring.cloud.gcp.spanner.project-id Facultatif. ID de projet Google Cloud. Remplace la valeur de spring.cloud.gcp.config.project-id.
spring.cloud.gcp.spanner.instance-id ID de l'instance Spanner.
spring.cloud.gcp.spanner.database Base de données à laquelle se connecter.

Données Spanner du modèle

Avec Spring Data Spanner, vous pouvez utiliser des POJO (Plain Old Java Objects, anciens objets Java standards) pour modéliser les données que vous stockez dans vos tables Spanner.

Pour chaque table de votre base de données, déclarez une entité qui représente un enregistrement dans cette table. Utilisez des annotations pour mapper l'entité et ses propriétés sur une table et ses colonnes.

Vous pouvez utiliser les annotations suivantes pour modéliser des relations simples entre des entités et des tables :

Annotations d'entités
@Column(name = "columnName")

Facultatif. Mappe la propriété sur une colonne spécifique de la table Spanner, en remplaçant la stratégie de dénomination qui mappe automatiquement les noms.

Lorsque vous omettez cette propriété, la stratégie d'attribution de noms par défaut pour Spring Data Spanner mappe les noms de propriété Java camelCase aux noms de colonnes PascalCase. Par exemple, la propriété singerId correspond au nom de la colonne SingerId.

@Embedded

Indique que la propriété est un objet encapsulé pouvant contenir les composants d'une clé primaire. Si la propriété est réellement utilisée dans la clé primaire, vous devez également inclure l'annotation @PrimaryKey.

@Interleaved

@Interleaved(lazy = true)

Indique qu'une propriété contient une liste de lignes entrelacées avec la ligne actuelle.

Par défaut, Spring Data Spanner récupère les lignes entrelacées lors de la création de l'instance. Pour récupérer les lignes tardivement, lorsque vous accédez à la propriété, utilisez @Interleaved(lazy = true).

Exemple : Si une entité Singer peut contenir des entrées entrelacées Album en tant qu'enfants, ajoutez une propriété List<Album> à l'entité Singer. Ajoutez également une annotation @Interleaved à la propriété.

@NotMapped

Indique qu'une propriété n'est pas stockée dans la base de données et doit être ignorée.

@PrimaryKey

@PrimaryKey(keyOrder = N)

Indique que la propriété est un composant de la clé primaire et identifie la position de la propriété dans la clé primaire, en partant de 1. La valeur keyOrder par défaut est 1.

Exemple : @PrimaryKey(keyOrder = 3)

@Table(name = "TABLE_NAME")

La table que modélise l'entité. Chaque instance de l'entité représente un enregistrement dans la table. Remplacez TABLE_NAME par le nom de votre table.

Exemple : @Table(name = "Singers")

Si vous devez modéliser des relations plus complexes, consultez la documentation de référence sur Spring Data Spanner pour en savoir plus sur les autres annotations compatibles avec le module.

Les exemples suivants illustrent une façon de modéliser les tables Singers et Albums pour Spring Data Spanner:

  • Pour les entités Singer, l'exemple inclut une propriété albums, avec une annotation @Interleaved. Cette propriété contient une liste d'albums entrelacés avec l'entité Singer. Spring Data Spanner insère automatiquement cette propriété.
  • Pour les entités Album, l'exemple inclut une propriété relatedAlbums qui n'est pas stockée dans 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;
  }
}

Interroger et modifier des données

Pour interroger et modifier des données avec Spring Data Spanner, vous pouvez acquérir un bean SpannerTemplate, qui met en œuvre SpannerOperations. SpannerTemplate fournit des méthodes permettant d'effectuer des requêtes SQL et de modifier des données à l'aide d'instructions LMD (langage de manipulation de données). Vous pouvez également utiliser ce bean pour accéder à l'API de lecture et à l'API Mutation pour Spanner.

De plus, vous pouvez étendre l'interface SpannerRepository pour encapsuler toute la logique d'application qui interroge et modifie les données dans Spanner.

Les sections suivantes expliquent comment utiliser SpannerTemplate et SpannerRepository.

Obtenir un modèle de bean

Utilisez l'annotation @Autowired pour acquérir automatiquement un bean SpannerTemplate. Vous pouvez ensuite utiliser SpannerTemplate dans votre classe.

L'exemple suivant illustre l'acquisition et l'utilisation du bean dans une classe :

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

}

Le bean SpannerTemplate permet d'exécuter des transactions en lecture seule et des transactions en lecture/écriture. En outre, l'annotation @Transactional permet de créer des transactions déclaratives.

Acquérir un bean de dépôt

Si vous utilisez un SpannerRepository, vous pouvez vous servir de l'annotation @Autowired pour acquérir un bean qui met en œuvre l'interface de votre dépôt. Un dépôt inclut des méthodes permettant d'exécuter des fonctions Java en tant que transactions en lecture seule et transactions en lecture/écriture. Pour les opérations de niveau inférieur, vous pouvez obtenir le modèle de bean utilisé par le dépôt.

Les exemples suivants montrent l'interface d'un dépôt, ainsi que l'acquisition et l'utilisation du bean dans une classe :

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

}

Gérer Spanner

Pour obtenir des informations sur vos bases de données Spanner, mettre à jour un schéma avec une instruction LDD (langage de définition de données) ou effectuer d'autres tâches administratives, vous pouvez obtenir un bean SpannerDatabaseAdminTemplate.

Utilisez l'annotation @Autowired pour acquérir automatiquement le bean. Vous pouvez ensuite utiliser SpannerDatabaseAdminTemplate dans votre classe.

L'exemple suivant illustre l'acquisition et l'utilisation du bean dans une classe :

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

Étapes suivantes