1. Übersicht
Hibernate ist zur De-facto-Standard-ORM-Lösung für Java-Projekte geworden. Es unterstützt alle wichtigen relationalen Datenbanken und ermöglicht noch leistungsstärkere ORM-Tools wie Spring Data JPA. Darüber hinaus gibt es viele mit Hibernate kompatible Frameworks wie Spring Boot, Microprofile und Quarkus.
Der Cloud Spanner-Dialekt für Hibernate ORM ermöglicht die Verwendung von Hibernate mit Cloud Spanner. Sie profitieren von den Vorteilen von Cloud Spanner – Skalierbarkeit und relationale Semantik – mit der idiomatischen Persistenz von Hibernate. Dies kann Ihnen helfen, vorhandene Anwendungen in die Cloud zu migrieren oder neue zu schreiben. Dabei profitieren Sie von der höheren Produktivität der Entwickler, die sich durch die Hibernate-basierten Technologien ergeben.
Aufgaben in diesem Lab
- Einfache Hibernate-Anwendung schreiben, die eine Verbindung zu Cloud Spanner herstellt
- Cloud Spanner-Datenbank erstellen
- So verwenden Sie den Cloud Spanner-Dialekt für Hibernate ORM
- So implementieren Sie CRUD-Vorgänge (create-read-update-delete) mit Hibernate
Voraussetzungen
2. Einrichtung und Anforderungen
Umgebung für das selbstbestimmte 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 ein Konto 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 in diesem Codelab später als PROJECT_ID
bezeichnet.
- Als Nächstes müssen Sie in der Cloud Console die Abrechnung aktivieren, um Google Cloud-Ressourcen nutzen zu können.
Dieses Codelab sollte ohne großen Aufwand betrieben werden. Folgen Sie der Anleitung im Abschnitt „Bereinigen“, . Hier erfahren Sie, wie Sie Ressourcen herunterfahren, damit Ihnen über dieses Tutorial hinaus keine Kosten entstehen. Neue Google Cloud-Nutzer können an einem kostenlosen Testzeitraum mit 300$Guthaben teilnehmen.
Cloud Shell aktivieren
- Klicken Sie in der Cloud Console auf Cloud Shell aktivieren .
Wenn Sie Cloud Shell zum ersten Mal verwenden, wird ein Zwischenbildschirm (below the fold) angezeigt, in dem beschrieben wird, worum es sich dabei handelt. Klicken Sie in diesem Fall auf Weiter. Der Chat wird nie wieder angezeigt. So sieht dieser einmalige Bildschirm aus:
Die Bereitstellung und Verbindung mit Cloud Shell dauert nur einen Moment.
Diese virtuelle Maschine verfügt über sämtliche Entwicklertools, die Sie benötigen. Es bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und wird in Google Cloud ausgeführt. Dadurch werden die Netzwerkleistung und die Authentifizierung erheblich verbessert. Viele, wenn nicht sogar alle Arbeiten in diesem Codelab können Sie ganz einfach mit einem Browser oder Ihrem Chromebook erledigen.
Sobald Sie mit Cloud Shell verbunden sind, sollten Sie sehen, dass Sie bereits authentifiziert sind und dass das Projekt bereits auf Ihre Projekt-ID eingestellt ist.
- Führen Sie in 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 Sie 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
Jetzt müssen wir dieser Instanz eine Datenbank hinzufügen. Wir nennen sie 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 zum Anwendungsverzeichnis.
cd spanner-hibernate-codelab
Kompilieren Sie die Anwendung und führen Sie sie 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 genauer an. Öffnen Sie dazu den Cloud Shell-Editor und suchen Sie im Verzeichnis spanner-hibernate-codelab
.
Bisher haben wir nur eine einfache Java-Konsolenanwendung, die "Hello World!"
ausgibt. Wir möchten jedoch eine Java-Anwendung schreiben, die Hibernate für die Kommunikation mit Cloud Spanner verwendet. Dazu benötigen wir den Cloud Spanner-Dialekt für Hibernate, den JDBC-Treiber von Cloud Spanner und den Hibernate-Kern. Fügen wir also die folgenden Abhängigkeiten in den <dependencies>
-Block in der Datei pom.xml
ein.
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
Also informieren wir Hibernate über die mit Annotationen versehenen Entitätsklassen, die wir der Datenbank zuordnen. Dazu geben wir hibernate.cfg.xml
ein. Die Entitätsklassen werden später erstellt.
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 außerdem wissen, wie eine Verbindung zur Cloud Spanner-Instanz hergestellt wird und welcher Dialekt verwendet werden soll. Also weisen wir ihn an, die SpannerDialect
für die SQL-Syntax, den Spanner-JDBC-Treiber und den JDBC-Verbindungsstring mit den Datenbankkoordinaten zu verwenden. Dieser wird in die Datei hibernate.properties
eingefügt.
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, die Sie mit dem folgenden Befehl abrufen können:
gcloud config get-value project
Da kein Datenbankschema vorhanden ist, haben wir das Attribut hibernate.hbm2ddl.auto=update
hinzugefügt, damit Hibernate die beiden Tabellen in Cloud Spanner erstellen kann, wenn wir die Anwendung zum ersten Mal ausführen.
In der Regel sollten Sie auch dafür sorgen, dass die Anmeldedaten für die Authentifizierung eingerichtet werden. Verwenden Sie dazu entweder eine JSON-Datei des Dienstkontos in der Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS
oder die Standardanmeldedaten für Anwendungen, die mit dem Befehl gcloud auth application-default login
konfiguriert wurden. Da die Ausführung in Cloud Shell erfolgt, sind jedoch bereits Standardanmeldedaten für das Projekt eingerichtet.
7. Annotierte Entitätsklassen erstellen
Jetzt können wir 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 Singer
s auch Listen von Album
s mit einer @OneToMany
-Anmerkung zuordnen 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.
Erstellen Sie die Kursdateien.
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 wir in diesem Beispiel eine automatisch generierte UUID für den Primärschlüssel verwenden. Dies ist ein bevorzugter ID-Typ in Cloud Spanner, da damit Hotspots vermieden werden, da das System die Daten zwischen den Servern nach Schlüsselbereichen aufteilt. Ein kontinuierlich ansteigender Ganzzahlschlüssel würde auch funktionieren, kann jedoch weniger leistungsfähig sein.
8. Entitäten speichern und abfragen
Wenn alles konfiguriert und die Entitätsobjekte definiert sind, können wir mit dem Schreiben in die Datenbank und Abfragen beginnen. Wir öffnen eine Hibernate-Session
und verwenden diese, um zuerst alle Tabellenzeilen in der clearData()
-Methode zu löschen, einige Entitäten in der writeData()
-Methode zu speichern und einige Abfragen mit der Hibernate-Abfragesprache (HQL) in der readData()
-Methode 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;
}
}
}
Lassen Sie uns nun den Code kompilieren und ausführen. Wir fügen die Option -Dexec.cleanupDaemonThreads=false
hinzu, um Warnungen zur Bereinigung von Daemon-Threads zu unterdrücken, die von Maven versucht wird.
mvn compile exec:java -Dexec.mainClass=codelab.App -Dexec.cleanupDaemonThreads=false
Die Ausgabe sollte in etwa so aussehen:
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 nun die Cloud Spanner-Konsole aufrufen und die Daten für die Tabellen "Singer" und "Album" in der Datenbank aufrufen, erhalten Sie eine Ausgabe wie diese:
9. Bereinigen
Löschen Sie die anfangs erstellte Cloud Spanner-Instanz, um sicherzustellen, dass sie keine unnötigen Ressourcen verbraucht.
gcloud spanner instances delete codelab-instance
10. Glückwunsch
Herzlichen Glückwunsch. Sie haben erfolgreich eine Java-Anwendung erstellt, die Hibernate verwendet, um Daten in Cloud Spanner zu speichern.
- Sie haben eine Cloud Spanner-Instanz und eine Datenbank erstellt
- Sie haben die Anwendung für die Verwendung von Hibernate konfiguriert.
- Sie haben zwei Elemente 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 zum Schreiben einer Hibernate-Anwendung mit Cloud Spanner.