1. Genel Bakış
Hibernate, Java projeleri için fiilen standart ORM çözümü haline geldi. Büyük ilişkisel veritabanlarının tümünü destekler ve Spring Data JPA gibi daha da güçlü ORM araçları sunar. Buna ek olarak Spring Boot, Microprofile ve Quarkus gibi Hibernate ile uyumlu birçok çerçeve vardır.
Hibernate ORM için Cloud Spanner Diyalect, Hibernate'i Cloud Spanner ile birlikte kullanmayı mümkün kılar. Hibernate'in deyimsel kalıcılığıyla Cloud Spanner'ın (ölçeklenebilirlik ve ilişkisel anlamlar) avantajlarından yararlanırsınız. Bu program, mevcut uygulamaları buluta taşımanıza veya Hibernate tabanlı teknolojilerin sağladığı artırılmış geliştirici üretkenliğinden yararlanarak yeni uygulamalar yazmanıza yardımcı olabilir.
Neler öğreneceksiniz?
- Cloud Spanner'a bağlanan basit bir Hibernate uygulaması yazma
- Cloud Spanner veritabanı oluşturma
- Hibernate ORM için Cloud Spanner Diyalektini kullanma
- Hibernate ile create-read-update-delete (CRUD) işlemlerini uygulama
Gerekenler
2. Kurulum ve Gereksinimler
Kendi hızınızda ortam kurulumu
- Cloud Console'da oturum açıp yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. (Gmail veya G Suite hesabınız yoksa hesap oluşturmanız gerekir.)
Tüm Google Cloud projelerinde benzersiz bir ad olan proje kimliğini unutmayın (yukarıdaki ad zaten alınmış ve size uygun olmayacaktır!). Bu kod laboratuvarın ilerleyen bölümlerinde PROJECT_ID
olarak adlandırılacaktır.
- Sonraki adımda, Google Cloud kaynaklarını kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir.
Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. "Temizleme" bölümündeki talimatları izlediğinizden emin olun. bölümünde, bu eğiticinin dışında faturalandırmayla karşılaşmamanız için kaynakları nasıl kapatacağınız konusunda tavsiyelerde bulunuyoruz. Yeni Google Cloud kullanıcıları 300 ABD doları ücretsiz deneme programından yararlanabilir.
Cloud Shell'i etkinleştirme
- Cloud Console'da, Cloud Shell'i etkinleştir
simgesini tıklayın.
Cloud Shell'i daha önce hiç çalıştırmadıysanız ne olduğunu açıklayan bir ara ekran (ekranın alt kısmında) gösterilir. Bu durumda Devam'ı tıklayın (bunu bir daha görmezsiniz). Tek seferlik ekran şöyle görünür:
Temel hazırlık ve Cloud Shell'e bağlanmak yalnızca birkaç dakika sürer.
İhtiyacınız olan tüm geliştirme araçlarını bu sanal makinede bulabilirsiniz. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud'da çalışarak ağ performansını ve kimlik doğrulamasını büyük ölçüde iyileştirir. Bu codelab'deki çalışmalarınızın tamamı olmasa bile büyük bir kısmı yalnızca bir tarayıcı veya Chromebook'unuzla yapılabilir.
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin proje kimliğinize ayarlandığını görürsünüz.
- Kimlik doğrulamanızın tamamlandığını onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud auth list
Komut çıkışı
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
gcloud config list project
Komut çıkışı
[core] project = <PROJECT_ID>
Doğru değilse aşağıdaki komutla ayarlayabilirsiniz:
gcloud config set project <PROJECT_ID>
Komut çıkışı
Updated property [core/project].
3. Veritabanı oluşturun
Cloud Shell başlatıldıktan sonra, GCP projenizle etkileşime geçmek için gcloud
kullanmaya başlayabilirsiniz.
İlk olarak Cloud Spanner API'yi etkinleştirin.
gcloud services enable spanner.googleapis.com
Şimdi codelab-instance
adlı bir Cloud Spanner örneği oluşturalım.
gcloud spanner instances create codelab-instance \ --config=regional-us-central1 \ --description="Codelab Instance" --nodes=1
Şimdi bu örneğe veritabanı eklememiz gerekiyor. Adı codelab-db
olarak adlandıracağız.
gcloud spanner databases create codelab-db --instance=codelab-instance
4. Boş bir uygulama oluştur
Basit bir Java konsolu uygulaması oluşturmak için Maven Hızlı Başlangıç Arketip'ini kullanacağız.
mvn archetype:generate \ -DgroupId=codelab \ -DartifactId=spanner-hibernate-codelab \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DarchetypeVersion=1.4 \ -DinteractiveMode=false
Uygulama dizinine geçin.
cd spanner-hibernate-codelab
Maven kullanarak uygulamayı derleyip çalıştırın.
mvn compile exec:java -Dexec.mainClass=codelab.App
Konsolda Hello World!
yazdırılmış şekilde gösterilir.
5. Bağımlılıkları ekleme
Cloud Shell Düzenleyici'yi açıp spanner-hibernate-codelab
dizinine göz atarak kaynak kodu keşfedelim.
Şimdiye kadar "Hello World!"
yazdıran temel bir Java konsolu uygulamamız var. Ancak, Cloud Spanner ile iletişim kurmak için Hibernate'i kullanan bir Java uygulaması yazmak istiyoruz. Bunun için Hibernate için Cloud Spanner Dialect'e, Cloud Spanner JDBC sürücüsüne ve Hibernate çekirdeğine ihtiyacımız olacak. Şimdi pom.xml
dosyasının içindeki <dependencies>
bloğuna aşağıdaki bağımlılıkları ekleyelim.
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'yi yapılandırma
Sonra, hibernate.cfg.xml
ve hibernate.properties
Hibernate yapılandırma dosyalarını oluşturacağız. Boş dosyalar oluşturmak için aşağıdaki komutu çalıştırın ve ardından Cloud Shell Düzenleyici'yi kullanarak dosyaları düzenleyin.
mkdir src/main/resources \ && touch src/main/resources/hibernate.cfg.xml \ && touch src/main/resources/hibernate.properties
Şimdi, hibernate.cfg.xml
doldurarak veritabanına eşleyeceğimiz ek açıklamalı varlık sınıflarını Hibernate'e söyleyelim. (Varlık sınıflarını daha sonra oluşturacağız.)
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'in, Cloud Spanner örneğine nasıl bağlanacağını ve hangi diyalektin kullanılacağını da bilmesi gerekir. Bu nedenle, SQL söz dizimi için SpannerDialect
, Spanner JDBC sürücüsü ve veritabanı koordinatlarıyla JDBC bağlantı dizesi kullanmasını söyleyeceğiz. Bu, hibernate.properties
dosyasına gider.
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
{PROJECT_ID}
öğesini, aşağıdaki komutu çalıştırarak alabileceğiniz proje kimliğinizle değiştirmeyi unutmayın:
gcloud config get-value project
Mevcut bir veritabanı şemamız olmadığından, uygulamayı ilk kez çalıştırdığımızda Hibernate'in Cloud Spanner'da iki tabloyu oluşturabilmesi için hibernate.hbm2ddl.auto=update
özelliğini ekledik.
Genellikle, kimlik doğrulama kimlik bilgilerinin GOOGLE_APPLICATION_CREDENTIALS
ortam değişkenindeki bir hizmet hesabı JSON dosyası veya gcloud auth application-default login
komutu kullanılarak yapılandırılan uygulama varsayılan kimlik bilgileri kullanılarak oluşturulduğundan emin olmanız gerekir. Ancak Cloud Shell'de çalıştığımız için varsayılan proje kimlik bilgileri zaten ayarlanmış.
7. Ek açıklamalı varlık sınıfları oluşturma
Şimdi kod yazmaya hazırız.
Cloud Spanner'daki tablolarla eşlenecek iki adet düz eski Java nesnesi (POJO) tanımlayacağız (Singer
ve Album
). Album
, Singer
ile @ManyToOne
ilişkisine sahip olacak. Ayrıca, Singer
öğelerini @OneToMany
ek açıklamasıyla Album
listelerine eşleyebilirdik ancak bu örnekte veritabanından bir şarkıcı getirmemiz gerektiğinde tüm albümleri yüklemeyi istemeyiz.
Singer
ve Album
varlık sınıflarını ekleyin.
Sınıf dosyalarını oluşturun.
touch src/main/java/codelab/Singer.java \ && touch src/main/java/codelab/Album.java
Dosyaların içeriğini yapıştırın.
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;
}
}
Bu örnekte, birincil anahtar için otomatik olarak oluşturulan bir UUID kullandığımıza dikkat edin. Bu, sistem verileri sunucular arasında anahtar aralıklarına göre bölerken hotspot'lardan kaçındığı için Cloud Spanner'da tercih edilen bir kimlik türüdür. Monoton olarak artan tam sayı anahtarları da işe yarar ancak daha düşük performanslı olabilir.
8. Varlıkları kaydetme ve sorgulama
Her şey yapılandırıldıktan ve varlık nesneleri tanımlandıktan sonra veritabanına yazmaya ve sorgulamaya başlayabiliriz. Bir Hibernate Session
açacak ve ardından bunu, ilk olarak clearData()
yöntemindeki tüm tablo satırlarını silmek, writeData()
yönteminde bazı varlıkları kaydetmek ve readData()
yönteminde Hibernate sorgu dilini (HQL) kullanarak bazı sorguları çalıştırmak için kullanacağız.
App.java
içeriğini şununla değiştirin:
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;
}
}
}
Şimdi kodu derleyip çalıştıralım. Maven'in yapmaya çalışacağı arka plan ileti dizileriyle ilgili uyarıları engellemek için -Dexec.cleanupDaemonThreads=false
seçeneğini ekleyeceğiz.
mvn compile exec:java -Dexec.mainClass=codelab.App -Dexec.cleanupDaemonThreads=false
Çıkışta şuna benzer bir şey görürsünüz:
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
Bu noktada, Cloud Spanner konsoluna gidip veritabanındaki Şarkıcı ve Albüm tablolarının verilerini görüntülerseniz aşağıdakine benzer bir tablo görürsünüz:
9. Temizleme
Başta oluşturduğumuz Cloud Spanner örneğini silerek, kaynakları gereksiz yere kullanmadığından emin olalım.
gcloud spanner instances delete codelab-instance
10. Tebrikler
Tebrikler, verileri Cloud Spanner'da tutmak için Hibernate'i kullanan bir Java uygulamasını başarıyla derlediniz.
- Cloud Spanner örneği ve veritabanı oluşturdunuz
- Uygulamayı Hibernate'i kullanacak şekilde yapılandırdınız
- Sanatçı ve Albüm olmak üzere iki öğe oluşturdunuz.
- Uygulamanızın veritabanı şemasını otomatik olarak oluşturdunuz
- Varlıkları başarıyla Cloud Spanner'a kaydettiniz ve sorguladınız
Artık Cloud Spanner ile Hibernate uygulaması yazmak için gereken temel adımları biliyorsunuz.