1. Genel Bakış
Hibernate, Java projeleri için fiili standart ORM çözümü haline geldi. Tüm büyük ilişkisel veritabanlarını destekler ve Spring Data JPA gibi daha da güçlü ORM araçlarını etkinleştirir. Ayrıca Spring Boot, Microprofile ve Quarkus gibi Hibernate ile uyumlu birçok çerçeve vardır.
Hibernate ORM için Cloud Spanner Dialect, Hibernate'in Cloud Spanner ile kullanılmasını sağlar. Hibernate'in deyimsel kalıcılığıyla Cloud Spanner'ın ölçeklenebilirlik ve ilişkisel semantik gibi avantajlarından yararlanabilirsiniz. Bu, mevcut uygulamaları buluta taşımanıza veya Hibernate tabanlı teknolojilerin sağladığı artan 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 Dialect'i kullanma
- Hibernate ile oluşturma, okuma, güncelleme ve silme (CRUD) işlemlerini uygulama
Gerekenler
2. Kurulum ve Gereksinimler
Yönlendirmesiz ortam kurulumu
- Cloud Console'da oturum açın ve 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.)
Proje kimliğini unutmayın. Bu kimlik, tüm Google Cloud projelerinde benzersiz bir addır (Yukarıdaki ad zaten alınmış olduğundan sizin için çalışmayacaktır). Bu codelab'in ilerleyen kısımlarında PROJECT_ID olarak adlandırılacaktır.
- Ardından, Google Cloud kaynaklarını kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir.
Bu codelab'i tamamlamak neredeyse hiç maliyetli değildir. Bu eğitimin ötesinde faturalandırma ücreti alınmaması için kaynakları nasıl kapatacağınız konusunda size tavsiyelerde bulunan "Temizleme" bölümündeki talimatları uyguladığınızdan emin olun. Google Cloud'un yeni kullanıcıları 300 ABD doları değerinde ücretsiz deneme programından yararlanabilir.
Cloud Shell'i etkinleştirme
- Cloud Console'da Cloud Shell'i etkinleştir 'i
tıklayın.
Cloud Shell'i daha önce hiç başlatmadıysanız ne olduğunu açıklayan bir ara ekran (ekranın alt kısmı) gösterilir. Bu durumda Devam'ı tıkladığınızda bu ekranı bir daha görmezsiniz. Bu tek seferlik ekran aşağıdaki gibi görünür:
Cloud Shell'in temel hazırlığı ve bağlanması yalnızca birkaç dakikanızı alır.
Bu sanal makine, ihtiyaç duyacağınız tüm geliştirme araçlarını içerir. 5 GB boyutunda kalıcı bir ana dizin bulunur ve Google Cloud'da çalışır. Bu sayede ağ performansı ve kimlik doğrulama önemli ölçüde güçlenir. Bu codelab'deki çalışmalarınızın neredeyse tamamını yalnızca bir tarayıcı veya Chromebook'unuzla yapabilirsiniz.
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin, proje kimliğinize ayarlandığını görürsünüz.
- Kimliğinizin doğrulandığını onaylamak için Cloud Shell'de şu 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>
Değilse şu 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şim kurmak için gcloud kullanmaya başlayabilirsiniz.
Öncelikle 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 bir veritabanı eklememiz gerekiyor. Buna codelab-db adını vereceğiz.
gcloud spanner databases create codelab-db --instance=codelab-instance
4. Boş bir uygulama oluşturma
Basit bir Java konsol uygulaması oluşturmak için Maven Quickstart Archetype'ı 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ı derleyin ve çalıştırın.
mvn compile exec:java -Dexec.mainClass=codelab.App
Konsolda Hello World! yazısını görmeniz gerekir.
5. Bağımlılık ekleme
Cloud Shell Düzenleyici'yi açıp spanner-hibernate-codelab dizininde gezinerek kaynak kodu inceleyelim.

Şu ana kadar yalnızca "Hello World!" yazdıran temel bir Java konsol uygulamamız var. Ancak, Cloud Spanner ile iletişim kurmak için Hibernate kullanan bir Java uygulaması yazmak istiyoruz. Bunun için Hibernate için Cloud Spanner Dialect, Cloud Spanner JDBC sürücüsü ve Hibernate çekirdeği gerekir. Bu nedenle, pom.xml dosyasındaki <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
Ardından, Hibernate yapılandırma dosyaları hibernate.cfg.xml ve hibernate.properties 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
Bu nedenle, hibernate.cfg.xml alanını doldurarak Hibernate'e veritabanıyla eşleyeceğimiz ek açıklamalı öğe sınıfları hakkında bilgi verelim. (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 diyalekti kullanacağını da bilmesi gerekir. Bu nedenle, SQL söz dizimi için SpannerDialect, Spanner JDBC sürücüsü ve veritabanı koordinatlarını içeren JDBC bağlantı dizesini kullanmasını söyleyeceğiz. Bu, hibernate.properties dosyasına girilir.
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} yerine proje kimliğinizi yazmayı unutmayın. Proje kimliğinizi almak için aşağıdaki komutu çalıştırabilirsiniz:
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 tablo oluşturmasına olanak tanımak 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 varsayılan uygulama kimlik bilgileri kullanılarak ayarlandığından da emin olursunuz. Ancak Cloud Shell'de çalıştığımız için varsayılan proje kimlik bilgileri zaten ayarlanmıştır.
7. Açıklamalı varlık sınıfları oluşturma
Artık kod yazmaya hazırız.
Cloud Spanner'daki tablolarla eşlenecek iki düz eski Java nesnesi (POJO) tanımlayacağız: Singer ve Album. Album, Singer ile @ManyToOne ilişkisine sahip olur. Singer öğelerini @OneToMany ek açıklamasıyla Album listeleriyle de eşleyebilirdik ancak bu örnekte, veritabanından bir şarkıcı getirmemiz gerektiğinde her seferinde tüm albümleri yüklemek istemiyoruz.
Singer ve Album öğe 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ızı unutmayın. Bu, Cloud Spanner'da tercih edilen bir kimlik türüdür. Sistem, verileri anahtar aralıklarına göre sunucular arasında böldüğü için bu türde etkin noktalar oluşmaz. Tekdüze olarak artan bir tam sayı anahtarı da işe yarayabilir ancak daha düşük performans gösterebilir.
8. Varlıkları kaydetme ve sorgulama
Her şey yapılandırılıp varlık nesneleri tanımlandıktan sonra veritabanına yazmaya ve veritabanını sorgulamaya başlayabiliriz. Bir Hibernate Session açıp 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 dosyasının içeriğini aşağıdakiyle 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ğı daemon iş parçacıkları temizliğiyle ilgili uyarıları bastırmak için -Dexec.cleanupDaemonThreads=false seçeneğini ekleyeceğiz.
mvn compile exec:java -Dexec.mainClass=codelab.App -Dexec.cleanupDaemonThreads=false
Çıkışta aşağıdakine benzer bir şey görmelisiniz:
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 Console'a gidip veritabanındaki Singer ve Album tablolarının verilerini görüntülerseniz şuna benzer bir şey görürsünüz:


9. Temizleme
Gereksiz yere kaynak tüketmemesi için başlangıçta oluşturduğumuz Cloud Spanner örneğini silelim.
gcloud spanner instances delete codelab-instance
10. Tebrikler
Tebrikler. Verileri Cloud Spanner'da kalıcı hale getirmek için Hibernate'i kullanan bir Java uygulamasını başarıyla oluşturdunuz.
- Cloud Spanner örneği ve veritabanı oluşturmuş olmanız gerekir.
- Uygulamayı Hibernate kullanacak şekilde yapılandırdıysanız
- Sanatçı ve Albüm olmak üzere iki varlık oluşturdunuz
- Uygulamanızın veritabanı şemasını otomatik olarak oluşturduysanız
- Varlıkları Cloud Spanner'a başarıyla kaydettiniz ve sorguladınız.
Artık Cloud Spanner ile Hibernate uygulaması yazmak için gereken temel adımları biliyorsunuz.