Integrate Spanner with Spring Data

The Spring Data Spanner module helps you use Spanner in any Java application that's built with the Spring Framework .

Like all Spring Data modules, Spring Data Spanner provides a Spring-based programming model that retains the consistency guarantees and scalability of Spanner. Its features are similar to Spring Data JPA and Hibernate ORM , with annotations designed for Spanner. For more information about how to use Spring Data JPA with Spanner, see Integrate Spanner with Spring Data JPA (GoogleSQL dialect) .

If you're already familiar with Spring, then Spring Data Spanner can make it easier to work with Spanner in your application and reduce the amount of code that you need to write.

This page explains how to add Spring Data Spanner to a Java application. For detailed information about the module, see the Spring Data Spanner reference .

Install the module

If you use Maven, add the Spring Cloud GCP Bill of Materials (BOM) and Spring Data Spanner to your pom.xml file. These dependencies provide the Spring Data Spanner components to your 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> 

You must also create a service account and use the service account key to authenticate with Google Cloud.

For more information, see the instructions for setting up a Java development environment . You do not need to install the Google Cloud Client Library for Java; the Spring Boot starter installs the client library automatically.

Configure the module

This section describes some of the most commonly used configuration settings for Spring Data Spanner. For a complete list of settings, see the reference documentation .

Specify an instance and database

To specify the default instance and database, set the following configuration properties for your application:

Property Description
spring.cloud.gcp.spanner.project-id Optional. The Google Cloud project ID. Overrides the value of spring.cloud.gcp.config.project-id .
spring.cloud.gcp.spanner.instance-id The Spanner instance ID.
spring.cloud.gcp.spanner.database The database to connect to.

Model Spanner data

With Spring Data Spanner, you can use plain old Java objects (POJOs) to model the data you store in your Spanner tables.

For each table in your database, declare an entity that represents a record in that table. Use annotations to map the entity and its properties to a table and its columns.

You can use the following annotations to model simple relationships between entities and tables:

Entity annotations
@Column(name = " columnName ")

Optional. Maps the property to a specific column in the Spanner table, overriding the naming strategy that automatically maps the names.

When you omit this property, the default naming strategy for Spring Data Spanner maps Java camelCase property names to PascalCase column names. For example, the property singerId maps to the column name SingerId .

@Embedded

Indicates that the property is an embedded object that can hold components of a primary key. If the property is actually used in the primary key, you must also include the @PrimaryKey annotation.

@Interleaved

@Interleaved(lazy = true )

Indicates that a property contains a list of rows that are interleaved with the current row.

By default, Spring Data Spanner fetches the interleaved rows at instance creation. To fetch the rows lazily, when you access the property, use @Interleaved(lazy = true) .

Example: If a Singer entity can have interleaved Album entries as children, add a List<Album> property to the Singer entity. Also, add an @Interleaved annotation to the property.

@NotMapped

Indicates that a property is not stored in the database and should be ignored.

@PrimaryKey

@PrimaryKey(keyOrder = N )

Indicates that the property is a component of the primary key, and identifies the position of the property within the primary key, starting at 1. The default keyOrder is 1 .

Example: @PrimaryKey(keyOrder = 3)

@Table(name = " TABLE_NAME ")

The table that the entity models. Each instance of the entity represents a record in the table. Replace TABLE_NAME with the name of your table.

Example: @Table(name = "Singers")

If you need to model more complex relationships, see the Spring Data Spanner reference for details about other annotations that the module supports.

The following examples show one way to model the Singers and Albums tables for Spring Data Spanner:

  • For Singer entities, the example includes an albums property, with an @Interleaved annotation. This property contains a list of albums that are interleaved with the Singer entity. Spring Data Spanner populates this property automatically.
  • For Album entities, the example includes a relatedAlbums property that is not stored in 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 
 ; 
  
 } 
 } 
 

Query and modify data

To query and modify data with Spring Data Spanner, you can acquire a SpannerTemplate bean, which implements SpannerOperations . SpannerTemplate provides methods for performing SQL queries and modifying data with Data Manipulation Language (DML) statements . You can also use this bean to access the read API and mutation API for Spanner.

In addition, you can extend the SpannerRepository interface to encapsulate all of the application logic that queries and modifies data in Spanner.

The following sections explain how to work with SpannerTemplate and SpannerRepository .

Acquire a template bean

Use the @Autowired annotation to acquire a SpannerTemplate bean automatically. You can then use the SpannerTemplate throughout your class.

The following example shows a class that acquires and uses the 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 
 )); 
  
 } 
 } 
 

You can use the SpannerTemplate bean to execute read-only transactions and read-write transactions . In addition, you can use the @Transactional annotation to create declarative transactions.

Acquire a repository bean

If you use a SpannerRepository , you can use the @Autowired annotation to acquire a bean that implements your repository's interface. A repository includes methods for running Java functions as read-only transactions and read-write transactions . For lower-level operations, you can get the template bean that the repository uses.

The following examples show the interface for a repository and a class that acquires and uses the 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" 
 ); 
  
 } 
 } 
 

Manage Spanner

To get information about your Spanner databases, update a schema with a Data Definition Language (DDL) statement, or complete other administrative tasks, you can acquire a SpannerDatabaseAdminTemplate bean.

Use the @Autowired annotation to acquire the bean automatically. You can then use the SpannerDatabaseAdminTemplate throughout your class.

The following example shows a class that acquires and uses the 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 
 ); 
  
 } 
  
 } 
 } 
 

What's next

Design a Mobile Site
View Site in Mobile | Classic
Share by: