Skip to content

jose-solorzano/google-cloud-spanner-hibernate

 
 

Repository files navigation

Google Cloud Spanner Dialect for Hibernate ORM

experimental

This is a dialect compatible with Hibernate 5.4 for the Google Cloud Spanner database service. The SpannerDialect 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.

Quick Set-Up

Maven coordinates for the dialect:

<dependency>
  <groupId>com.google.cloud</groupId>
  <artifactId>google-cloud-spanner-hibernate-dialect</artifactId>
  <version> TBD </version>
</dependency>

Maven coordinates for the official open source Cloud Spanner JDBC Driver:

<dependency>
  <groupId>com.google.cloud</groupId>
  <artifactId>google-cloud-spanner-jdbc</artifactId>
  <version>0.1.0</version>
</dependency>

Configuring the SpannerDialect and a Cloud Spanner Driver class is typical of all Hibernate dialects in the hibernate.properties file:

hibernate.dialect=com.google.cloud.spanner.hibernate.SpannerDialect
hibernate.connection.driver_class=com.google.cloud.spanner.jdbc.JdbcDriver
hibernate.connection.url=jdbc:cloudspanner:/projects/{INSERT_PROJECT_ID}/instances/{INSERT_INSTANCE_ID}/databases/{INSERT_DATABASE_ID}

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

The SpannerDialect supports most of the standard Hibernate and Java Persistence annotations but there are important differences in features because of differences in Cloud Spanner’s data model from traditional SQL databases.

These are unsupported features in the Cloud Spanner Hibernate Dialect. Please see the following sections for details:

Unsupported Feature Description

Constraints

No support for FOREIGN KEY, UNIQUE, or ON DELETE CASCADE. Cloud Spanner does not enforce relationship links outside of Hibernate.

Catalog and schema scoping for table names

Tables name references cannot contain periods or other punctuation.

Column default values

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 because Cloud Spanner doesn’t have SQL NUMERIC or DECIMAL support.

Relationships

The dialect supports all of the standard entity relationships:

  • @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.

Note
The lack of foreign key constraints also means database-side cascading deletes are not supported via the @OnDelete(action = OnDeleteAction.CASCADE) annotation because there is no ON DELETE CASCADE constraint in Cloud Spanner DDL. However, Hibernate-side cascading operations such as @ManyToOne(cascade = {CascadeType.ALL}) are supported.

Constraints

Cloud Spanner does not support database constraints. As a result, SpannerDialect does not currently support any constraints such as FOREIGN KEY, UNIQUE, or ON DELETE CASCADE.

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.

The lack of the foreign key constraint affects relationships and collection properties annotated with @ElementCollection.

Generated IDs

Hibernate’s @GeneratedValue annotation for long properties is supported but not recommended:

@Entity
public class Employee {

  @Id
  @GeneratedValue // DON'T DO THIS, IT'S SLOW
  public Long id;
}

This results in sequential IDs that are not optimal for Cloud Spanner and requires locking of the hibernate_sequence table for inserts.

You should use locally-generated UUID key values instead:

@Entity
public class Employee {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Type(type="uuid-char")
  public 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.

Table Catalogs and Schemas

Cloud Spanner does not support table names with catalog and schema components:

// Not supported: `public.store.book` is not a valid Cloud Spanner table name reference.
@Table(
  catalog = "public",
  schema = "store",
  name = "book"
)

// Supported.
@Table(
  name = "book"
)

Column Default Values

The dialect does not currently set default values based on the @ColumnDefault annotation, because NULL values aren’t specially handled and are stored just like other values by Cloud Spanner and its driver.

Decimal and Numeric Types

Cloud Spanner does not provide native support for arbitrary-precision decimal numbers, such as NUMERIC and DECIMAL. As a result, the driver and dialect do not support decimal and arbitrary-precision Java types such as java.math.BigInteger and java.math.BigDecimal.

Subclasses using InheritanceType.JOINED

If you are using entities that are related by inheritance with the @Inheritance(strategy = InheritanceType.JOINED):

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Payment {

    @Id
    @GeneratedValue
    private Long id;

    private Long amount;
}

@Entity
public class WireTransferPayment extends Payment {
}

@Entity
public class CreditCardPayment extends Payment {
}

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

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.

About

The official Google Cloud Spanner Dialect for Hibernate ORM

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 99.4%
  • Shell 0.6%