This blog will show how to use Cloud Spanner, with Hibernate ORM, and Quarkus (in JVM mode). The complete example is on GitHub .

If you don’t already have a Google Cloud Platform account, you can sign up for free and receive $300 credit .

A Cloud Spanner instance can host multiple databases. Create a database to store the tables that we’ll generate through Hibernate. Create a database called people :

If you already have a database schema, you can import it via the command line too. In this example, we’ll let Hibernate create the schema instead.

Create a new single-node Cloud Spanner instance in the US Central1 region. (You can find other regions to use ):

Currently, there is no official Cloud Spanner emulator for local development. In order to try out Cloud Spanner, you’ll need to create a server instance. To complete this tutorial, you’ll need:

Create a new Quarkus application

Use Maven to create a new Quarkus application:

mvn io.quarkus:quarkus-maven-plugin:1.0.1.Final:create \ -DprojectGroupId=com.example \ -DprojectArtifactId=spanner-example \ -DclassName="com.example.PersonResource" -Dpath="/person"

Build the application:

cd spanner-example ./mvnw package

Add Hibernate ORM extension to the project:

./mvnw quarkus:add-extension -Dextension=quarkus-hibernate-orm

This will add the quarkus-hibernate-orm dependency in the pom.xml :

<dependency> <groupId> io.quarkus </groupId> <artifactId> quarkus-hibernate-orm </artifactId> </dependency>

Add both the Cloud Spanner JDBC driver and the Cloud Spanner Dialect dependencies to the pom.xml :

<!-- The Hibernate dialect for Spanner dependency --> <dependency> <groupId> com.google.cloud </groupId> <artifactId> google-cloud-spanner-hibernate-dialect </artifactId> <version> 1.0.0 </version> </dependency> <!-- The Spanner JDBC driver dependency --> <dependency> <groupId> com.google.cloud </groupId> <artifactId> google-cloud-spanner-jdbc </artifactId> <version> 1.11.0 </version> </dependency>

Configure Quarkus to use the JDBC driver, and also the Cloud Spanner Hibernate Dialect:

src/main/resources/application.properties quarkus.datasource.driver=com.google.cloud.spanner.jdbc.JdbcDriver quarkus.datasource.url=jdbc:cloudspanner:/projects/${PROJECT_ID}/instances/sample/databases/people quarkus.hibernate-orm.dialect=com.google.cloud.spanner.hibernate.SpannerDialect quarkus.hibernate-orm.database.generation=drop-and-create

Replace the ${PROJECT_ID} with your Google Cloud project ID.

When running the application locally (not running on Google Cloud), to have permissions to connect to your Spanner database you need to set the GOOGLE_APPLICATION_CREDENTIALS environment variable. See also Providing credentials to your application.

You can now create new JPA entities. Typically an entity uses an auto-increment numeric ID as a surrogate key. However, this is not the best choice when using Cloud Spanner. Cloud Spanner automatically organizes and distributes data across nodes based on the primary key in alphanumeric order, so you should not use any monotonically increasing/decreasing key (most commonly the auto-increment IDs). Such a key would create hotspots in Cloud Spanner, and introduce unnecessary bottlenecks during both data writes and ID generation, which ultimately will slow down performance and limit scalability. Cloud Spanner recommends the use of UUIDv4 as a primary key, so we’ll use that for the entity too.

Let’s create a Person entity:

src/main/java/com/example/Person.java package com.example ; import java.util.UUID ; import javax.persistence.Entity ; import javax.persistence.GeneratedValue ; import javax.persistence.GenerationType ; import javax.persistence.Id ; @Entity public class Person { @GeneratedValue (strategy = GenerationType.AUTO) @Type (type = " uuid-char " ) @Id private UUID id; private String name; public UUID getId() { return id; } public void setId( UUID id) { this .id = id; } public String getName() { return name; } public void setName( String name) { this .name = name; } }

Once the entity is created, then the rest is easy! Simply use a JPA Entity Manager perform CRUD operations with Cloud Spanner! Create a JAX-RS REST Resource to use JPA Entity Manager to save a new entry:

src/main/java/com/example/PersonResource.java package com.example ; import javax.inject.Inject ; import javax.persistence.EntityManager ; import javax.transaction.Transactional ; import javax.ws.rs.Consumes ; import javax.ws.rs.GET ; import javax.ws.rs.POST ; import javax.ws.rs.Path ; import javax.ws.rs.Produces ; import javax.ws.rs.core.MediaType ; @Path ( " /person " ) public class PersonResource { @Inject EntityManager entityManager; @POST @Transactional @Produces (MediaType.APPLICATION_JSON) @Consumes (MediaType.APPLICATION_JSON) public Person create(Person person) { entityManager.persist(person); return person; } }

Notice that the create method is annotated with @Transactional . This is because there is no auto-commit and writes must participate in a transaction. Cloud Spanner is fully transactional, and the Cloud Spanner JDBC driver exposes JTA semantics. Transaction annotations will work as JPA users would expect.

The create method also expects to receive a Person object as a JSON payload. You need to add RestEasy JSONB extension so Quarkus can convert JSON payloads to POJO:

./mvnw quarkus:add-extension -Dextension=quarkus-resteasy-jsonb

Run this application in development mode:

./mvnw quarkus:dev

Once the application is up and running (at Quarkus' supersonic atomic speed!), use curl to post a JSON payload to the application:

curl -XPOST -H"Content-type: application/json" -d'{"name": "Ray"}' \ http://localhost:8080/person