১. সংক্ষিপ্ত বিবরণ
জাভা প্রোজেক্টের জন্য হাইবারনেট কার্যত আদর্শ ORM সলিউশন হয়ে উঠেছে। এটি সমস্ত প্রধান রিলেশনাল ডেটাবেস সমর্থন করে এবং Spring Data JPA-এর মতো আরও শক্তিশালী ORM টুল ব্যবহারের সুযোগ করে দেয়। এছাড়াও, Spring Boot, Microprofile, এবং Quarkus-এর মতো অনেক হাইবারনেট-সামঞ্জস্যপূর্ণ ফ্রেমওয়ার্ক রয়েছে।
ক্লাউড স্প্যানার ডায়ালেক্ট ফর হাইবারনেট ওআরএম (Cloud Spanner Dialect for Hibernate ORM) হাইবারনেটের সাথে ক্লাউড স্প্যানার ব্যবহার করা সম্ভব করে তোলে। এর মাধ্যমে আপনি ক্লাউড স্প্যানারের সুবিধাগুলো—যেমন স্কেলেবিলিটি এবং রিলেশনাল সিম্যান্টিকস—হাইবারনেটের ইডিওম্যাটিক পারসিস্টেন্সের সাথে একত্রে পাবেন। এটি আপনাকে বিদ্যমান অ্যাপ্লিকেশনগুলোকে ক্লাউডে মাইগ্রেট করতে অথবা হাইবারনেট-ভিত্তিক প্রযুক্তির মাধ্যমে ডেভেলপারদের বর্ধিত উৎপাদনশীলতাকে কাজে লাগিয়ে নতুন অ্যাপ্লিকেশন তৈরি করতে সাহায্য করতে পারে।
আপনি যা শিখবেন
- কীভাবে একটি সহজ হাইবারনেট অ্যাপ্লিকেশন লিখবেন যা ক্লাউড স্প্যানারের সাথে সংযোগ স্থাপন করে
- ক্লাউড স্প্যানার ডাটাবেস কীভাবে তৈরি করবেন
- হাইবারনেট ORM-এর জন্য ক্লাউড স্প্যানার ডায়ালেক্ট কীভাবে ব্যবহার করবেন
- হাইবারনেট ব্যবহার করে কীভাবে ক্রিয়েট-রিড-আপডেট-ডিলিট (CRUD) অপারেশনগুলো বাস্তবায়ন করা যায়
আপনার যা যা লাগবে
- একটি গুগল ক্লাউড প্ল্যাটফর্ম প্রকল্প
- একটি ব্রাউজার, যেমন ক্রোম বা ফায়ারফক্স
২. সেটআপ এবং প্রয়োজনীয়তা
স্ব-গতিতে পরিবেশ সেটআপ
- ক্লাউড কনসোলে সাইন ইন করুন এবং একটি নতুন প্রজেক্ট তৈরি করুন অথবা বিদ্যমান কোনো প্রজেক্ট পুনরায় ব্যবহার করুন। (যদি আপনার আগে থেকে Gmail বা G Suite অ্যাকাউন্ট না থাকে, তবে আপনাকে অবশ্যই একটি তৈরি করতে হবে।)
প্রজেক্ট আইডিটি মনে রাখবেন, যা সমস্ত গুগল ক্লাউড প্রজেক্ট জুড়ে একটি অনন্য নাম (উপরের নামটি ইতিমধ্যে ব্যবহৃত হয়েছে এবং আপনার জন্য কাজ করবে না, দুঃখিত!)। এই কোডল্যাবে এটিকে পরবর্তীতে PROJECT_ID হিসাবে উল্লেখ করা হবে।
- এরপরে, গুগল ক্লাউড রিসোর্স ব্যবহার করার জন্য আপনাকে ক্লাউড কনসোলে বিলিং চালু করতে হবে।
এই কোডল্যাবটি চালাতে খুব বেশি খরচ হওয়ার কথা নয়, এমনকি আদৌ কোনো খরচ নাও হতে পারে। "পরিষ্কার-পরিচ্ছন্নতা" (Cleaning up) বিভাগে দেওয়া নির্দেশাবলী অবশ্যই অনুসরণ করবেন, যেখানে রিসোর্স বন্ধ করার পরামর্শ দেওয়া হয়েছে, যাতে এই টিউটোরিয়ালের বাইরে আপনার কোনো বিল না আসে। গুগল ক্লাউডের নতুন ব্যবহারকারীরা ৩০০ মার্কিন ডলারের ফ্রি ট্রায়াল প্রোগ্রামের জন্য যোগ্য।
ক্লাউড শেল সক্রিয় করুন
- ক্লাউড কনসোল থেকে, Activate Cloud Shell-এ ক্লিক করুন।
.
আপনি যদি আগে কখনো ক্লাউড শেল চালু না করে থাকেন, তাহলে এটি কী তা বর্ণনা করে একটি মধ্যবর্তী স্ক্রিন (নিচে দেওয়া আছে) আপনার সামনে আসবে। যদি তাই হয়, তাহলে 'Continue'-তে ক্লিক করুন (এবং আপনি এটি আর কখনো দেখতে পাবেন না)। একবারের জন্য আসা সেই স্ক্রিনটি দেখতে এইরকম:
ক্লাউড শেল প্রস্তুত করতে এবং এর সাথে সংযোগ স্থাপন করতে মাত্র কয়েক মুহূর্ত সময় লাগা উচিত।
এই ভার্চুয়াল মেশিনটিতে আপনার প্রয়োজনীয় সমস্ত ডেভেলপমেন্ট টুলস লোড করা আছে। এটি একটি স্থায়ী ৫ জিবি হোম ডিরেক্টরি প্রদান করে এবং গুগল ক্লাউডে চলে, যা নেটওয়ার্ক পারফরম্যান্স ও অথেনটিকেশনকে ব্যাপকভাবে উন্নত করে। এই কোডল্যাবে আপনার প্রায় সমস্ত কাজই শুধুমাত্র একটি ব্রাউজার বা আপনার ক্রোমবুক দিয়ে করা সম্ভব।
ক্লাউড শেলে সংযুক্ত হওয়ার পর আপনি দেখতে পাবেন যে, আপনাকে ইতিমধ্যেই প্রমাণীকৃত করা হয়েছে এবং প্রজেক্টটি আপনার প্রজেক্ট আইডিতে সেট করা আছে।
- আপনি প্রমাণীকৃত কিনা তা নিশ্চিত করতে ক্লাউড শেলে নিম্নলিখিত কমান্ডটি চালান:
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].
৩. একটি ডাটাবেস তৈরি করুন
ক্লাউড শেল চালু হওয়ার পর, আপনি আপনার GCP প্রোজেক্টের সাথে কাজ করার জন্য gcloud ব্যবহার শুরু করতে পারেন।
প্রথমে ক্লাউড স্প্যানার এপিআই (Cloud Spanner API) সক্রিয় করুন।
gcloud services enable spanner.googleapis.com
এখন, 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
৪. একটি খালি অ্যাপ তৈরি করুন
আমরা 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! লেখাটি দেখতে পাবেন।
৫. নির্ভরতা যোগ করুন
চলুন ক্লাউড শেল এডিটর খুলে spanner-hibernate-codelab ডিরেক্টরির ভেতরে ব্রাউজ করে সোর্স কোডটি অন্বেষণ করি।

এখন পর্যন্ত, আমাদের কাছে শুধু একটি সাধারণ জাভা কনসোল অ্যাপ আছে যা "Hello World!" প্রিন্ট করে। কিন্তু, আমরা এমন একটি জাভা অ্যাপ্লিকেশন তৈরি করতে চাই যা ক্লাউড স্প্যানারের সাথে যোগাযোগের জন্য হাইবারনেট ব্যবহার করবে। এর জন্য আমাদের ক্লাউড স্প্যানার ডায়ালেক্ট ফর হাইবারনেট, ক্লাউড স্প্যানার জেডিবিসি ড্রাইভার এবং হাইবারনেট কোর প্রয়োজন হবে। সুতরাং, pom.xml ফাইলের <dependencies> ব্লকে নিম্নলিখিত ডিপেন্ডেন্সিগুলো যোগ করা যাক।
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>
৬. হাইবারনেট ORM কনফিগার করুন
এরপরে, আমরা hibernate.cfg.xml এবং hibernate.properties নামে হাইবারনেট কনফিগারেশন ফাইল তৈরি করব। খালি ফাইলগুলো তৈরি করতে নিচের কমান্ডটি চালান এবং তারপর ক্লাউড শেল এডিটর ব্যবহার করে সেগুলো সম্পাদনা করুন।
mkdir src/main/resources \ && touch src/main/resources/hibernate.cfg.xml \ && touch src/main/resources/hibernate.properties
সুতরাং, hibernate.cfg.xml ফাইলটি পূরণ করে আমরা Hibernate-কে সেইসব অ্যানোটেড এনটিটি ক্লাস সম্পর্কে জানাই যেগুলোকে আমরা ডাটাবেসের সাথে ম্যাপ করব। (এনটিটি ক্লাসগুলো আমরা পরে তৈরি করব।)
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>
ক্লাউড স্প্যানার ইনস্ট্যান্সের সাথে কীভাবে সংযোগ স্থাপন করতে হবে এবং কোন ডায়ালেক্ট ব্যবহার করতে হবে, তা-ও হাইবারনেটের জানা প্রয়োজন। তাই, আমরা এটিকে SQL সিনট্যাক্সের জন্য SpannerDialect , স্প্যানার 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
মনে রাখবেন, {PROJECT_ID} এর জায়গায় আপনার প্রজেক্ট আইডি বসাতে হবে, যা আপনি নিচের কমান্ডটি চালিয়ে পেতে পারেন:
gcloud config get-value project
যেহেতু আমাদের কোনো বিদ্যমান ডাটাবেস স্কিমা নেই, তাই আমরা hibernate.hbm2ddl.auto=update প্রপার্টিটি যোগ করেছি, যাতে অ্যাপটি প্রথমবার চালানোর সময় হাইবারনেট ক্লাউড স্প্যানারে দুটি টেবিল তৈরি করে নেয়।
সাধারণত, আপনাকে GOOGLE_APPLICATION_CREDENTIALS এনভায়রনমেন্ট ভেরিয়েবলে একটি সার্ভিস অ্যাকাউন্ট JSON ফাইল ব্যবহার করে অথবা gcloud auth application-default login কমান্ড ব্যবহার করে কনফিগার করা অ্যাপ্লিকেশনের ডিফল্ট ক্রেডেনশিয়াল দিয়ে অথেনটিকেশন ক্রেডেনশিয়াল সেট আপ করা আছে কিনা তাও নিশ্চিত করতে হবে। তবে, যেহেতু আমরা ক্লাউড শেলে কাজ করছি, তাই প্রজেক্টের ডিফল্ট ক্রেডেনশিয়াল আগে থেকেই সেট আপ করা আছে।
৭. অ্যানোটেড এনটিটি ক্লাস তৈরি করুন
এখন আমরা কোড লেখার জন্য প্রস্তুত।
আমরা দুটি সাধারণ জাভা অবজেক্ট (POJO) সংজ্ঞায়িত করব যা ক্লাউড স্প্যানারের টেবিল— Singer এবং Album সাথে ম্যাপ করা থাকবে। Album এর সাথে Singer একটি @ManyToOne সম্পর্ক থাকবে। আমরা @OneToMany অ্যানোটেশন ব্যবহার করে Singer গুলোকে তাদের 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 ব্যবহার করছি। ক্লাউড স্প্যানারে এটি একটি পছন্দের আইডি টাইপ, কারণ সিস্টেমটি কী রেঞ্জ অনুযায়ী সার্ভারগুলোর মধ্যে ডেটা ভাগ করে দেওয়ায় এটি হটস্পট এড়াতে সাহায্য করে। একমুখী ক্রমবর্ধমান পূর্ণসংখ্যার কী-ও কাজ করবে, কিন্তু সেটির পারফরম্যান্স কম হতে পারে।
৮. সত্তাগুলি সংরক্ষণ এবং অনুসন্ধান করুন
সবকিছু কনফিগার করা এবং এনটিটি অবজেক্টগুলো সংজ্ঞায়িত করা হয়ে গেলে, আমরা ডাটাবেসে লেখা এবং কোয়েরি করা শুরু করতে পারি। আমরা একটি হাইবারনেট Session খুলব এবং তারপর সেটি ব্যবহার করে প্রথমে clearData() মেথডে টেবিলের সমস্ত সারি মুছে ফেলব, writeData() মেথডে কিছু এনটিটি সংরক্ষণ করব এবং readData() মেথডে হাইবারনেট কোয়েরি ল্যাঙ্গুয়েজ (HQL) ব্যবহার করে কিছু কোয়েরি চালাব।
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 অপশনটি যোগ করব, যা 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
এই পর্যায়ে, আপনি যদি ক্লাউড স্প্যানার কনসোলে গিয়ে ডাটাবেসের Singer এবং Album টেবিলের ডেটা দেখেন, তাহলে এইরকম কিছু দেখতে পাবেন:


৯. পরিষ্কার করুন
শুরুতে তৈরি করা ক্লাউড স্প্যানার ইনস্ট্যান্সটি ডিলিট করে দেওয়া যাক, যাতে এটি অপ্রয়োজনীয়ভাবে রিসোর্স ব্যবহার না করে।
gcloud spanner instances delete codelab-instance
১০. অভিনন্দন
অভিনন্দন, আপনি সফলভাবে একটি জাভা অ্যাপ্লিকেশন তৈরি করেছেন যা ক্লাউড স্প্যানারে ডেটা সংরক্ষণের জন্য হাইবারনেট ব্যবহার করে।
- আপনি একটি ক্লাউড স্প্যানার ইনস্ট্যান্স এবং একটি ডাটাবেস তৈরি করেছেন
- আপনি অ্যাপ্লিকেশনটি হাইবারনেট ব্যবহার করার জন্য কনফিগার করেছেন।
- আপনি দুটি সত্তা তৈরি করেছেন: শিল্পী এবং অ্যালবাম
- আপনি আপনার অ্যাপ্লিকেশনের জন্য ডাটাবেস স্কিমা স্বয়ংক্রিয়ভাবে তৈরি করেছেন।
- আপনি সফলভাবে ক্লাউড স্প্যানারে এনটিটিগুলো সংরক্ষণ করেছেন এবং সেগুলো কোয়েরি করেছেন।
ক্লাউড স্প্যানার ব্যবহার করে হাইবারনেট অ্যাপ্লিকেশন লেখার জন্য প্রয়োজনীয় মূল ধাপগুলো এখন আপনি জানেন।