1. بررسی اجمالی
Hibernate تبدیل به راه حل استاندارد ORM برای پروژه های جاوا شده است. این از همه پایگاه داده های رابطه ای اصلی پشتیبانی می کند و ابزارهای ORM قدرتمندتری مانند Spring Data JPA را فعال می کند. علاوه بر این، بسیاری از فریمورکهای سازگار با Hibernate مانند Spring Boot، Microprofile و Quarkus وجود دارد.
Cloud Spanner Dialect برای Hibernate ORM امکان استفاده از Hibernate با Cloud Spanner را فراهم می کند. با تداوم اصطلاحی Hibernate، از مزایای Cloud Spanner - مقیاسپذیری و معناشناسی رابطهای برخوردار میشوید. این میتواند به شما کمک کند برنامههای موجود را به ابر منتقل کنید یا برنامههای جدیدی بنویسید که بهرهوری توسعهدهنده افزایش یافته توسط فناوریهای مبتنی بر Hibernate فراهم میشود.
چیزی که یاد خواهید گرفت
- چگونه یک برنامه Hibernate ساده بنویسیم که به Cloud Spanner متصل می شود
- نحوه ایجاد پایگاه داده Cloud Spanner
- نحوه استفاده از گویش Cloud Spanner برای Hibernate ORM
- نحوه اجرای عملیات ایجاد، خواندن، بهروزرسانی، حذف (CRUD) با Hibernate
آنچه شما نیاز دارید
2. راه اندازی و الزامات
تنظیم محیط خود به خود
- به کنسول Cloud وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. (اگر قبلاً یک حساب Gmail یا G Suite ندارید، باید یک حساب ایجاد کنید .)
شناسه پروژه را به خاطر بسپارید، یک نام منحصر به فرد در تمام پروژه های Google Cloud (نام بالا قبلاً گرفته شده است و برای شما کار نخواهد کرد، متأسفیم!). بعداً در این آزمایشگاه کد به عنوان PROJECT_ID
نامیده خواهد شد.
- در مرحله بعد، برای استفاده از منابع Google Cloud، باید صورتحساب را در Cloud Console فعال کنید .
اجرا کردن از طریق این کد لبه نباید هزینه زیادی داشته باشد، اگر اصلاً باشد. حتماً دستورالعملهای موجود در بخش «تمیز کردن» را دنبال کنید که به شما توصیه میکند چگونه منابع را خاموش کنید تا بیش از این آموزش متحمل صورتحساب نشوید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.
Cloud Shell را فعال کنید
- از Cloud Console، روی Activate Cloud Shell کلیک کنید .
اگر قبلاً Cloud Shell را راهاندازی نکردهاید، با یک صفحه میانی (زیر تاشو) روبرو میشوید که آن را توصیف میکند. اگر اینطور است، روی Continue کلیک کنید (و دیگر آن را نخواهید دید). در اینجا به نظر می رسد که آن صفحه یک بار مصرف:
تهیه و اتصال به Cloud Shell فقط باید چند لحظه طول بکشد.
این ماشین مجازی با تمام ابزارهای توسعه که شما نیاز دارید بارگذاری شده است. این دایرکتوری اصلی 5 گیگابایتی دائمی را ارائه می دهد و در Google Cloud اجرا می شود و عملکرد شبکه و احراز هویت را بسیار افزایش می دهد. بیشتر، اگر نه همه، کار شما در این کد لبه را می توان به سادگی با یک مرورگر یا Chromebook انجام داد.
پس از اتصال به Cloud Shell، باید ببینید که قبلاً احراز هویت شده اید و پروژه قبلاً روی ID پروژه شما تنظیم شده است.
- برای تایید احراز هویت، دستور زیر را در Cloud Shell اجرا کنید:
gcloud auth list
خروجی فرمان
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
gcloud config list project
خروجی فرمان
[core] project = <PROJECT_ID>
اگر اینطور نیست، می توانید آن را با این دستور تنظیم کنید:
gcloud config set project <PROJECT_ID>
خروجی فرمان
Updated property [core/project].
3. یک پایگاه داده ایجاد کنید
پس از راه اندازی Cloud Shell، می توانید از gcloud
برای تعامل با پروژه GCP خود استفاده کنید.
ابتدا Cloud Spanner API را فعال کنید.
gcloud services enable spanner.googleapis.com
اکنون، بیایید یک نمونه Cloud Spanner به نام codelab-instance
ایجاد کنیم.
gcloud spanner instances create codelab-instance \ --config=regional-us-central1 \ --description="Codelab Instance" --nodes=1
اکنون باید یک پایگاه داده به این نمونه اضافه کنیم. ما آن را codelab-db
می نامیم.
gcloud spanner databases create codelab-db --instance=codelab-instance
4. یک برنامه خالی ایجاد کنید
ما از Maven Quickstart Archetype برای ایجاد یک برنامه کنسول جاوا ساده استفاده خواهیم کرد.
mvn archetype:generate \ -DgroupId=codelab \ -DartifactId=spanner-hibernate-codelab \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DarchetypeVersion=1.4 \ -DinteractiveMode=false
به فهرست برنامه تغییر دهید.
cd spanner-hibernate-codelab
برنامه را با استفاده از Maven کامپایل و اجرا کنید.
mvn compile exec:java -Dexec.mainClass=codelab.App
شما باید Hello World!
چاپ شده در کنسول
5. وابستگی ها را اضافه کنید
بیایید کد منبع را با باز کردن Cloud Shell Editor و مرور در دایرکتوری spanner-hibernate-codelab
بررسی کنیم.
تا کنون، ما فقط یک برنامه پایه کنسول جاوا داریم که "Hello World!"
. با این حال، ما واقعاً می خواهیم یک برنامه جاوا بنویسیم که از Hibernate برای صحبت با Cloud Spanner استفاده کند. برای آن، به گویش Cloud Spanner برای Hibernate، درایور Cloud Spanner JDBC و هسته Hibernate نیاز داریم. بنابراین، اجازه دهید وابستگی های زیر را به بلوک <dependencies>
داخل فایل pom.xml
اضافه کنیم.
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 را پیکربندی کنید
در مرحله بعد، فایل های پیکربندی Hibernate hibernate.cfg.xml
و hibernate.properties
را ایجاد می کنیم. دستور زیر را برای ایجاد فایل های خالی اجرا کنید و سپس با استفاده از Cloud Shell Editor آنها را ویرایش کنید.
mkdir src/main/resources \ && touch src/main/resources/hibernate.cfg.xml \ && touch src/main/resources/hibernate.properties
بنابراین، اجازه دهید به Hibernate درباره کلاسهای موجودیت حاشیهنویسی که با پر کردن hibernate.cfg.xml
به پایگاه داده نگاشت میکنیم، بگوییم. (ما بعداً کلاس های موجودیت را ایجاد خواهیم کرد.)
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 همچنین باید بداند که چگونه به نمونه Cloud Spanner وصل شود و از کدام گویش استفاده کند. بنابراین، به آن میگوییم که از SpannerDialect
برای نحو SQL، درایور Spanner JDBC و رشته اتصال JDBC با مختصات پایگاه داده استفاده کند. این به فایل hibernate.properties
می رود.
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
به یاد داشته باشید که ID پروژه خود را جایگزین {PROJECT_ID}
کنید، که با اجرای دستور زیر می توانید آن را دریافت کنید:
gcloud config get-value project
از آنجایی که ما یک طرح پایگاه داده موجود نداریم، ویژگی hibernate.hbm2ddl.auto=update
را اضافه کردیم تا به Hibernate اجازه دهیم وقتی برنامه را برای اولین بار اجرا می کنیم، دو جدول را در Cloud Spanner ایجاد کند.
معمولاً، با استفاده از یک فایل JSON حساب سرویس در متغیر محیطی GOOGLE_APPLICATION_CREDENTIALS
یا با استفاده از مجوزهای پیشفرض برنامه که با استفاده از دستور gcloud auth application-default login
پیکربندی شدهاند، مطمئن شوید که اعتبارنامههای احراز هویت تنظیم شدهاند. با این حال، از آنجایی که ما در Cloud Shell در حال اجرا هستیم، اعتبار پروژه پیشفرض از قبل تنظیم شده است.
7. کلاس های موجودیت مشروح ایجاد کنید
حالا ما آماده ایم تا مقداری کد بنویسیم.
ما دو شیء قدیمی جاوا (POJOs) را تعریف می کنیم که به جداول در Cloud Spanner نگاشت می شوند - Singer
و Album
. Album
یک رابطه @ManyToOne
با Singer
خواهد داشت. همچنین میتوانستیم Singer
را با حاشیهنویسی @OneToMany
به فهرست Album
نگاشت کنیم، اما برای این مثال، ما واقعاً نمیخواهیم همه آلبومها را هر بار که نیاز به واکشی خواننده از پایگاه داده داریم، بارگیری کنیم.
کلاس های Singer
و Album
را اضافه کنید.
فایل های کلاس را ایجاد کنید.
touch src/main/java/codelab/Singer.java \ && touch src/main/java/codelab/Album.java
محتویات فایل ها را پیست کنید.
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;
}
}
توجه داشته باشید که برای این مثال ما از یک UUID تولید شده خودکار برای کلید اصلی استفاده می کنیم. این یک نوع شناسه ترجیحی در Cloud Spanner است، زیرا از نقاط مهم جلوگیری می کند زیرا سیستم داده ها را بین سرورها بر اساس محدوده کلید تقسیم می کند. یک کلید عدد صحیح به طور یکنواخت افزایش می یابد، اما می تواند عملکرد کمتری داشته باشد.
8. ذخیره و پرس و جو نهاد
با پیکربندی همه چیز و تعریف اشیاء موجودیت، می توانیم شروع به نوشتن در پایگاه داده و پرس و جو کردن آن کنیم. ما یک Session
Hibernate را باز می کنیم و سپس از آن برای حذف تمام ردیف های جدول در متد clearData()
استفاده می کنیم، برخی از موجودیت ها را در متد writeData()
ذخیره می کنیم و برخی از پرس و جوها را با استفاده از زبان Query Hibernate (HQL) در readData()
روش.
محتوای App.java
را با موارد زیر جایگزین کنید:
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;
}
}
}
حالا بیایید کد را کامپایل و اجرا کنیم. ما گزینه -Dexec.cleanupDaemonThreads=false
را اضافه می کنیم تا هشدارهای مربوط به پاکسازی موضوعات daemon را که Maven سعی می کند انجام دهد، سرکوب می کنیم.
mvn compile exec:java -Dexec.mainClass=codelab.App -Dexec.cleanupDaemonThreads=false
در خروجی باید چیزی شبیه به این ببینید:
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
در این مرحله، اگر به کنسول Cloud Spanner بروید و دادههای جداول Singer و Album را در پایگاه داده مشاهده کنید، چیزی شبیه به این خواهید دید:
9. پاکسازی کنید
بیایید نمونه Cloud Spanner را که در ابتدا ایجاد کرده بودیم حذف کنیم تا مطمئن شویم که منابع را بی جهت مصرف نمی کند.
gcloud spanner instances delete codelab-instance
10. تبریک می گویم
تبریک میگوییم، شما با موفقیت یک برنامه جاوا ساختهاید که از Hibernate برای تداوم دادهها در Cloud Spanner استفاده میکند.
- شما یک نمونه Cloud Spanner و یک پایگاه داده ایجاد کردید
- شما برنامه را برای استفاده از Hibernate پیکربندی کرده اید
- شما دو موجودیت ایجاد کردید: Artist و Album
- شما به طور خودکار طرح پایگاه داده را برای برنامه خود ایجاد کردید
- شما با موفقیت موجودیت ها را در Cloud Spanner ذخیره کردید و از آنها پرس و جو کردید
اکنون مراحل کلیدی مورد نیاز برای نوشتن یک برنامه Hibernate با Cloud Spanner را می دانید.