Hibernate ORM with Cloud Spanner

You can use Hibernate ORM with Cloud Spanner using the Cloud Spanner Dialect (SpannerDialect). Cloud Spanner Dialect is compatible with Hibernate ORM 5.4 for Google Cloud Spanner. Cloud Spanner Dialect produces SQL, DML, and DDL statements for most common entity types and relationships using standard Hibernate and Java Persistence annotations.

Please see the following sections for important details about dialect differences due to the unique features and limitations of Cloud Spanner.

Setting up Hibernate ORM with Cloud Spanner

Add the Apache Maven dependencies for Hibernate ORM core, Cloud Spanner Dialect, and the Cloud Spanner officially supported Open Source JDBC driver.

<dependencies>
  <!-- The Hibernate dialect for Spanner dependency -->
  <dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>google-cloud-spanner-hibernate-dialect</artifactId>
    <version>0.1.0</version>
  </dependency>

  <!-- The Spanner JDBC driver dependency -->
  <dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>google-cloud-spanner-jdbc</artifactId>
    <version>1.7.0</version>
  </dependency>

  <!-- Hibernate core dependency -->
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.4.6.Final</version>
  </dependency>
</dependencies>

Configure hibernate.cfg.xml to use Cloud Spanner Dialect and Cloud Spanner JDBC Driver.

<!-- Connection settings -->
<property name="hibernate.dialect">com.google.cloud.spanner.hibernate.SpannerDialect</property>
<property name="hibernate.connection.driver_class">com.google.cloud.spanner.jdbc.JdbcDriver</property>
<property name="hibernate.connection.url">jdbc:cloudspanner:/projects/{YOUR_PROJECT_ID}/instances/{YOUR_INSTANCE_ID}/databases/{YOUR_DATABASE_ID}</property>

The service account JSON credentials file location should be in the GOOGLE_APPLICATION_CREDENTIALS environment variable. The driver will use default credentials set in the Google Cloud SDK gcloud application otherwise.

The dialect and driver are compatible with all values (create, create-drop, and update) of the hibernate.hbm2ddl.auto setting.

Spanner dialect

SpannerDialect supports most of the standard Hibernate and Java Persistence API (JPA) annotations described in the Hibernate Reference Documentation. However, there are important differences in features due to differences in Cloud Spanner's data model from traditional SQL databases.

Unsupported features

Here is a summary of Hibernate features that are not supported in the Cloud Spanner Dialect.

Unsupported Feature Description
Constraints Cloud Spanner does not support database constraints. As a result, SpannerDialect does not support FOREIGN KEY, UNIQUE, and ON DELETE CASCADE. The lack of the foreign key constraint affects relationships and collection properties annotated with @ElementCollection.

Note: Hibernate doesn't directly rely on the existence of constraints to perform its operations and leaves the enforcement of relationship links to the database.
Catalog and schema scoping for table names Table name references cannot contain periods or other punctuation.
Column default values The dialect does not currently set default values based on the @ColumnDefault annotation. Cloud Spanner treats NULL like any other value and it gets no special handling.
Big-decimal or arbitrary-precision numbers The dialect does not support java.math.BigDecimal and java.math.BigInteger because Cloud Spanner does not provide native support for arbitrary-precision decimal numbers, such as NUMERIC or DECIMAL.
Interleaved tables Currently there is no support for Cloud Spanner's interleaved table feature. Hibernate ORM relationships are always constructed using join-tables and foreign keys by the framework. If your application would benefit from interleaved tables, we recommend that you manually create them and use types mapped to them in Hibernate. This enables the performance and database-enforced-constraint benefits from interleaved tables in Cloud Spanner, even though the Hibernate framework will not be aware of their relationship or any restrictions on operations between interleaved tables.
Simba JDBC Driver Hibernate ORM with Cloud Spanner is officially supported only with the open-source Cloud Spanner JDBC Driver. It does not support the Simba JDBC driver at this time.

Relationships

The dialect supports all of the standard entity relationship annotations:

  • @OneToOne
  • @OneToMany
  • @ManyToOne
  • @ManyToMany

These can be used via @JoinTable or @JoinColumn. However, because Cloud Spanner does not support foreign key constraints, foreign-key-columns are just regular columns in Cloud Spanner.

Optimizing queries

To take advantage of Cloud Spanner's full performance, consider using its SQL best practices.

Because Hibernate's built-in HQL does not account for Cloud Spanner-specific features, you can construct queries directly from Cloud Spanner SQL instead:

SQLQuery query = session.createSQLQuery("SELECT * FROM Singers AS s
                                         JOIN@{FORCE_JOIN_ORDER=TRUE} Albums AS a
                                         ON s.SingerId = a.Singerid
                                         WHERE s.LastName LIKE '%x%'
                                         AND a.AlbumTitle LIKE '%love%';");

Schema settings

Hibernate's hibernate.hbm2ddl.auto setting controls the framework's schema modification behavior that occurs during start-up. The following settings are available:

  • none: Do nothing.
  • validate: Validate the schema, makes no changes to the database.
  • update: Update the schema.
  • create: Create the schema, destroying previous data.
  • create-drop: Drop the schema when the SessionFactory is closed explicitly, typically when the application is stopped.

Hibernate performs schema updates on each table and entity type on startup, which can take more than several minutes if there are many tables. To avoid schema updates keeping Hibernate from starting for several minutes, you can update schemas separately and use the none or validate settings.

Generated IDs

Use locally-generated UUID key values to generate IDs.

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Type(type = "uuid-char")
private UUID id;

The @Type(type="uuid-char") annotation specifies that this UUID value will be stored in Cloud Spanner as a STRING column. Leaving out this annotation causes a BYTES column to be used.

Subclasses using InheritanceType.JOINED

This is how to use entities that are related by inheritance with the @Inheritance(strategy = InheritanceType.JOINED).

import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import org.hibernate.annotations.Type;

/**
 * An example {@link Entity} which demonstrates usage of {@link Inheritance}.
 */
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Payment {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Type(type = "uuid-char")
  private UUID id;

  private Long amount;

  public UUID getId() {
    return id;
  }

  public void setId(UUID id) {
    this.id = id;
  }

  public Long getAmount() {
    return amount;
  }

  public void setAmount(Long amount) {
    this.amount = amount;
  }
}

You must set the hibernate.hql.bulk_id_strategy setting in hibernate.properties to org.hibernate.hql.spi.id.inline.InlineIdsOrClauseBulkIdStrategy.

<!-- Modify the default bulk id strategy if using InheritanceType.JOINED with Spanner. -->
<property name="hibernate.hql.bulk_id_strategy">org.hibernate.hql.spi.id.inline.InlineIdsOrClauseBulkIdStrategy</property>

This is because Hibernate's default behavior (PersistentTableBulkIdStrategy) attempts to create intermediate tables to handle delete and update operations on the multiple tables that represent a JOINED inheritance hierarchy, but these table creations statements do not conform to Cloud Spanner DDL. Using one of the Inline bulk-ID strategy classes given above resolves this issue.

What's next

Was deze pagina nuttig? Laat ons weten hoe goed we u hebben geholpen:

Feedback verzenden over...

Cloud Spanner Documentation