1. Übersicht
Hibernate ist die De-facto-Standard-ORM-Lösung für Java-Projekte. Es unterstützt alle wichtigen relationalen Datenbanken und ermöglicht noch leistungsstärkere ORM-Tools wie Spring Data JPA. Außerdem gibt es viele mit Hibernate kompatible Frameworks wie Spring Boot, Microprofile und Quarkus.
Mit dem Cloud Spanner-Dialekt für Hibernate ORM können Sie Hibernate mit Cloud Spanner verwenden. Sie profitieren von den Vorteilen von Cloud Spanner – Skalierbarkeit und relationale Semantik – mit der idiomatischen Persistenz von Hibernate. So können Sie vorhandene Anwendungen in die Cloud migrieren oder neue Anwendungen schreiben, die von der erhöhten Entwicklerproduktivität profitieren, die auf Hibernate basierenden Technologien bieten.
Lerninhalte
- Eine einfache Hibernate-Anwendung schreiben, die eine Verbindung zu Cloud Spanner herstellt
- Cloud Spanner-Datenbank erstellen
- Cloud Spanner-Dialect für Hibernate ORM verwenden
- CRUD-Vorgänge (Create, Read, Update, Delete) mit Hibernate implementieren
Voraussetzungen
2. Einrichtung und Anforderungen
Umgebung zum selbstbestimmten Lernen einrichten
- Melden Sie sich in der Cloud Console an und erstellen Sie ein neues Projekt oder verwenden Sie ein vorhandenes Projekt. Wenn Sie noch kein Gmail- oder G Suite-Konto haben, müssen Sie eines erstellen.
Notieren Sie sich die Projekt-ID, also den projektübergreifend nur einmal vorkommenden Namen eines Google Cloud-Projekts. Der oben angegebene Name ist bereits vergeben und kann leider nicht mehr verwendet werden. Sie wird später in diesem Codelab als PROJECT_ID bezeichnet.
- Als Nächstes müssen Sie die Abrechnung in der Cloud Console aktivieren, um Google Cloud-Ressourcen verwenden zu können.
Die Durchführung dieses Codelabs sollte keine oder nur geringe Kosten verursachen. Folgen Sie bitte der Anleitung im Abschnitt „Bereinigen“, in der Sie erfahren, wie Sie Ressourcen herunterfahren können, damit nach Abschluss dieser Anleitung keine Gebühren anfallen. Neue Nutzer von Google Cloud kommen für das Programm für den kostenlosen Testzeitraum mit einem Guthaben von 300$ infrage.
Cloud Shell aktivieren
- Klicken Sie in der Cloud Console auf Cloud Shell aktivieren
.
Wenn Sie Cloud Shell noch nie gestartet haben, wird ein Fenster mit einer Beschreibung eingeblendet. Klicken Sie in diesem Fall einfach auf Weiter. So sieht dieses Fenster aus:
Das Herstellen der Verbindung mit der Cloud Shell sollte nur wenige Augenblicke dauern.
Diese virtuelle Maschine verfügt über sämtliche Entwicklertools, die Sie benötigen. Sie bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und läuft in Google Cloud, was die Netzwerkleistung und Authentifizierung erheblich verbessert. Die meisten, wenn nicht sogar alle Aufgaben in diesem Codelab können mit einem Browser oder Ihrem Chromebook erledigt werden.
Sobald die Verbindung mit der Cloud Shell hergestellt ist, sehen Sie, dass Sie bereits authentifiziert sind und für das Projekt schon Ihre Projekt-ID eingestellt ist.
- Führen Sie in der Cloud Shell den folgenden Befehl aus, um zu prüfen, ob Sie authentifiziert sind:
gcloud auth list
Befehlsausgabe
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
gcloud config list project
Befehlsausgabe
[core] project = <PROJECT_ID>
Ist dies nicht der Fall, können Sie die Einstellung mit diesem Befehl vornehmen:
gcloud config set project <PROJECT_ID>
Befehlsausgabe
Updated property [core/project].
3. Datenbank erstellen
Nach dem Start von Cloud Shell können Sie gcloud verwenden, um mit Ihrem GCP-Projekt zu interagieren.
Aktivieren Sie zuerst die Cloud Spanner API.
gcloud services enable spanner.googleapis.com
Erstellen wir nun eine Cloud Spanner-Instanz mit dem Namen codelab-instance.
gcloud spanner instances create codelab-instance \ --config=regional-us-central1 \ --description="Codelab Instance" --nodes=1
Als Nächstes müssen wir dieser Instanz eine Datenbank hinzufügen. Wir nennen es codelab-db.
gcloud spanner databases create codelab-db --instance=codelab-instance
4. Leere Anwendung erstellen
Wir verwenden den Maven-Schnellstart-Archetyp, um eine einfache Java-Konsolenanwendung zu erstellen.
mvn archetype:generate \ -DgroupId=codelab \ -DartifactId=spanner-hibernate-codelab \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DarchetypeVersion=1.4 \ -DinteractiveMode=false
Wechseln Sie in das App-Verzeichnis.
cd spanner-hibernate-codelab
Kompilieren und führen Sie die App mit Maven aus.
mvn compile exec:java -Dexec.mainClass=codelab.App
In der Konsole sollte Hello World! angezeigt werden.
5. Abhängigkeiten hinzufügen
Sehen wir uns den Quellcode an, indem wir den Cloud Shell-Editor öffnen und das Verzeichnis spanner-hibernate-codelab durchsuchen.

Bisher haben wir nur eine einfache Java-Konsolenanwendung, die "Hello World!" ausgibt. Wir möchten jedoch eine Java-Anwendung schreiben, die Hibernate verwendet, um mit Cloud Spanner zu kommunizieren. Dazu benötigen wir den Cloud Spanner-Dialekt für Hibernate, den Cloud Spanner-JDBC-Treiber und den Hibernate-Kern. Fügen wir also dem <dependencies>-Block in der Datei pom.xml die folgenden Abhängigkeiten hinzu.
pom.xml
<!-- Spanner Dialect -->
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner-hibernate-dialect</artifactId>
<version>1.5.0</version>
</dependency>
<!-- JDBC Driver -->
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner-jdbc</artifactId>
<version>2.0.0</version>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.29.Final</version>
</dependency>
6. Hibernate ORM konfigurieren
Als Nächstes erstellen wir die Hibernate-Konfigurationsdateien hibernate.cfg.xml und hibernate.properties. Führen Sie den folgenden Befehl aus, um die leeren Dateien zu erstellen, und bearbeiten Sie sie dann mit dem Cloud Shell-Editor.
mkdir src/main/resources \ && touch src/main/resources/hibernate.cfg.xml \ && touch src/main/resources/hibernate.properties
Wir müssen Hibernate also über die annotierten Entitätsklassen informieren, die wir der Datenbank zuordnen möchten. Dazu füllen wir hibernate.cfg.xml aus. Die Entitätsklassen erstellen wir später.
src/main/resources/hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<!-- Annotated entity classes -->
<mapping class="codelab.Album"/>
<mapping class="codelab.Singer"/>
</session-factory>
</hibernate-configuration>
Hibernate muss auch wissen, wie eine Verbindung zur Cloud Spanner-Instanz hergestellt wird und welcher Dialekt verwendet werden soll. Wir weisen das Tool also an, die SpannerDialect für die SQL-Syntax, den Spanner-JDBC-Treiber und den JDBC-Verbindungsstring mit den Datenbankkoordinaten zu verwenden. Diese Informationen werden in die Datei hibernate.properties aufgenommen.
src/main/resources/hibernate.properties
hibernate.dialect=com.google.cloud.spanner.hibernate.SpannerDialect
hibernate.connection.driver_class=com.google.cloud.spanner.jdbc.JdbcDriver
hibernate.connection.url=jdbc:cloudspanner:/projects/{PROJECT_ID}/instances/codelab-instance/databases/codelab-db
# auto-create or update DB schema
hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
Denken Sie daran, {PROJECT_ID} durch Ihre Projekt-ID zu ersetzen. Sie können sie mit dem folgenden Befehl abrufen:
gcloud config get-value project
Da wir kein vorhandenes Datenbankschema haben, haben wir die Property hibernate.hbm2ddl.auto=update hinzugefügt, damit Hibernate die beiden Tabellen in Cloud Spanner erstellt, wenn wir die App zum ersten Mal ausführen.
Normalerweise würden Sie auch dafür sorgen, dass die Anmeldedaten für die Authentifizierung eingerichtet sind. Dazu verwenden Sie entweder eine JSON-Datei für das Dienstkonto in der Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS oder die Standardanmeldedaten für Anwendungen, die mit dem Befehl gcloud auth application-default login konfiguriert wurden. Da wir jedoch in Cloud Shell ausgeführt werden, sind die Standardanmeldedaten für das Projekt bereits eingerichtet.
7. Annotierte Entitätsklassen erstellen
Jetzt können wir etwas Code schreiben.
Wir definieren zwei einfache alte Java-Objekte (POJOs), die Tabellen in Cloud Spanner zugeordnet werden: Singer und Album. Album hat eine @ManyToOne-Beziehung zu Singer. Wir hätten Singers auch mit einer @OneToMany-Anmerkung auf Listen ihrer Albums abbilden können, aber in diesem Beispiel möchten wir nicht jedes Mal alle Alben laden, wenn wir einen Sänger aus der Datenbank abrufen müssen.
Fügen Sie die Entitätsklassen Singer und Album hinzu.
Klassendateien erstellen
touch src/main/java/codelab/Singer.java \ && touch src/main/java/codelab/Album.java
Fügen Sie den Inhalt der Dateien ein.
src/main/java/codelab/Singer.java
package codelab;
import java.util.Date;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.Type;
@Entity
public class Singer {
@Id
@GeneratedValue
@Type(type = "uuid-char")
private UUID singerId;
private String firstName;
private String lastName;
@Temporal(TemporalType.DATE)
private Date birthDate;
public Singer() {
}
public Singer(String firstName, String lastName, Date birthDate) {
this.firstName = firstName;
this.lastName = lastName;
this.birthDate = birthDate;
}
public UUID getSingerId() {
return singerId;
}
public void setSingerId(UUID singerId) {
this.singerId = singerId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Singer)) {
return false;
}
Singer singer = (Singer) o;
if (!firstName.equals(singer.firstName)) {
return false;
}
if (!lastName.equals(singer.lastName)) {
return false;
}
return birthDate.equals(singer.birthDate);
}
@Override
public int hashCode() {
int result = firstName.hashCode();
result = 31 * result + lastName.hashCode();
result = 31 * result + birthDate.hashCode();
return result;
}
}
src/main/java/codelab/Album.java
package codelab;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.Type;
@Entity
public class Album {
@Id
@GeneratedValue
@Type(type = "uuid-char")
UUID albumId;
@ManyToOne
Singer singer;
String albumTitle;
public Album() {
}
public Album(Singer singer, String albumTitle) {
this.singer = singer;
this.albumTitle = albumTitle;
}
public UUID getAlbumId() {
return albumId;
}
public void setAlbumId(UUID albumId) {
this.albumId = albumId;
}
public Singer getSinger() {
return singer;
}
public void setSinger(Singer singer) {
this.singer = singer;
}
public String getAlbumTitle() {
return albumTitle;
}
public void setAlbumTitle(String albumTitle) {
this.albumTitle = albumTitle;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Album)) {
return false;
}
Album album = (Album) o;
if (!singer.equals(album.singer)) {
return false;
}
return albumTitle.equals(album.albumTitle);
}
@Override
public int hashCode() {
int result = singer.hashCode();
result = 31 * result + albumTitle.hashCode();
return result;
}
}
Beachten Sie, dass in diesem Beispiel eine automatisch generierte UUID für den Primärschlüssel verwendet wird. Dies ist der bevorzugte ID-Typ in Cloud Spanner, da er Hotspots vermeidet, weil das System Daten nach Schlüsselbereichen auf die Server verteilt. Ein monoton steigender Ganzzahlschlüssel würde auch funktionieren, kann aber weniger leistungsfähig sein.
8. Entitäten speichern und abfragen
Nachdem alles konfiguriert und die Entitätsobjekte definiert wurden, können wir mit dem Schreiben in die Datenbank und dem Abfragen der Datenbank beginnen. Wir öffnen eine Hibernate-Session und verwenden sie dann, um zuerst alle Tabellenzeilen in der Methode clearData() zu löschen, einige Entitäten in der Methode writeData() zu speichern und einige Abfragen mit der Hibernate-Abfragesprache (Hibernate Query Language, HQL) in der Methode readData() auszuführen.
Ersetzen Sie den Inhalt von App.java durch Folgendes:
src/main/java/codelab/App.java
package codelab;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class App {
public final static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
public static void main(String[] args) {
// create a Hibernate sessionFactory and session
StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(registry).buildMetadata()
.buildSessionFactory();
Session session = sessionFactory.openSession();
clearData(session);
writeData(session);
readData(session);
// close Hibernate session and sessionFactory
session.close();
sessionFactory.close();
}
private static void clearData(Session session) {
session.beginTransaction();
session.createQuery("delete from Album where 1=1").executeUpdate();
session.createQuery("delete from Singer where 1=1").executeUpdate();
session.getTransaction().commit();
}
private static void writeData(Session session) {
session.beginTransaction();
Singer singerMelissa = new Singer("Melissa", "Garcia", makeDate("1981-03-19"));
Album albumGoGoGo = new Album(singerMelissa, "Go, Go, Go");
session.save(singerMelissa);
session.save(albumGoGoGo);
session.save(new Singer("Russell", "Morales", makeDate("1978-12-02")));
session.save(new Singer("Jacqueline", "Long", makeDate("1990-07-29")));
session.save(new Singer("Dylan", "Shaw", makeDate("1998-05-02")));
session.getTransaction().commit();
}
private static void readData(Session session) {
List<Singer> singers = session.createQuery("from Singer where birthDate >= '1990-01-01' order by lastName")
.list();
List<Album> albums = session.createQuery("from Album").list();
System.out.println("Singers who were born in 1990 or later:");
for (Singer singer : singers) {
System.out.println(singer.getFirstName() + " " + singer.getLastName() + " born on "
+ DATE_FORMAT.format(singer.getBirthDate()));
}
System.out.println("Albums: ");
for (Album album : albums) {
System.out
.println("\"" + album.getAlbumTitle() + "\" by " + album.getSinger().getFirstName() + " "
+ album.getSinger().getLastName());
}
}
private static Date makeDate(String dateString) {
try {
return DATE_FORMAT.parse(dateString);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
}
Kompilieren und führen wir den Code aus. Wir fügen die Option -Dexec.cleanupDaemonThreads=false hinzu, um Warnungen zum Bereinigen von Daemon-Threads zu unterdrücken, die Maven ausführen wird.
mvn compile exec:java -Dexec.mainClass=codelab.App -Dexec.cleanupDaemonThreads=false
In der Ausgabe sollte etwa Folgendes zu sehen sein:
Singers who were born in 1990 or later: Jacqueline Long born on 1990-07-29 Dylan Shaw born on 1998-05-02 Albums: "Go, Go, Go" by Melissa Garcia
Wenn Sie jetzt die Cloud Spanner-Konsole aufrufen und sich die Daten für die Tabellen „Singer“ und „Album“ in der Datenbank ansehen, sehen Sie etwa Folgendes:


9. Bereinigen
Löschen Sie die Cloud Spanner-Instanz, die Sie am Anfang erstellt haben, damit sie nicht unnötig Ressourcen verbraucht.
gcloud spanner instances delete codelab-instance
10. Glückwunsch
Sie haben erfolgreich eine Java-Anwendung erstellt, die mit Hibernate Daten in Cloud Spanner speichert.
- Sie haben eine Cloud Spanner-Instanz und eine Datenbank erstellt.
- Sie haben die Anwendung für die Verwendung von Hibernate konfiguriert.
- Sie haben zwei Einheiten erstellt: „Künstler“ und „Album“.
- Sie haben das Datenbankschema für Ihre Anwendung automatisch generiert.
- Sie haben Entitäten erfolgreich in Cloud Spanner gespeichert und abgefragt.
Sie kennen jetzt die wichtigsten Schritte, die zum Schreiben einer Hibernate-Anwendung mit Cloud Spanner erforderlich sind.