1. نظرة عامة
Cloud Spanner هي نظام إدارة قواعد بيانات علائقية (RDBMS) متاح بدرجة كبيرة وقابل للتوسيع أفقيًا ومتعدد المناطق. سيستخدم هذا الدرس التطبيقي أصغر مثيل من Cloud Spanner، ولكن لا تنسَ إيقافه عند الانتهاء.
ما ستتعلمه
- كيفية استخدام Cloud Spanner لحفظ البيانات واسترجاعها باستخدام Spring Boot
المتطلبات
كيف ستستخدم هذا البرنامج التعليمي؟
ما هو تقييمك لتجربة استخدام خدمات Google Cloud Platform؟
2. الإعداد والمتطلبات
إعداد البيئة بالسرعة التي تناسبك
- سجِّل الدخول إلى Cloud Console وأنشِئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. (إذا لم يكن لديك حساب على Gmail أو G Suite، عليك إنشاء حساب).
تذكَّر رقم تعريف المشروع، وهو اسم فريد في جميع مشاريع Google Cloud (الاسم أعلاه مستخدَم حاليًا ولن يكون متاحًا لك، نأسف لذلك). سيتم الإشارة إليه لاحقًا في هذا الدرس العملي باسم PROJECT_ID.
- بعد ذلك، عليك تفعيل الفوترة في Cloud Console من أجل استخدام موارد Google Cloud.
لن تكلفك تجربة هذا الدرس التطبيقي حول الترميز الكثير من المال، إن لم تكلفك شيئًا على الإطلاق. احرص على اتّباع أي تعليمات في قسم "التنظيف" الذي ينصحك بكيفية إيقاف الموارد حتى لا تتحمّل رسومًا تتجاوز هذا البرنامج التعليمي. يمكن لمستخدمي Google Cloud الجدد الاستفادة من برنامج الفترة التجريبية المجانية بقيمة 300 دولار أمريكي.
تفعيل Cloud Shell
- من Cloud Console، انقر على تفعيل Cloud Shell
.
إذا لم يسبق لك بدء Cloud Shell، ستظهر لك شاشة وسيطة (الجزء السفلي غير المرئي من الصفحة) توضّح ماهيته. في هذه الحالة، انقر على متابعة (ولن تظهر لك مرة أخرى). في ما يلي الشكل الذي ستظهر به هذه الشاشة لمرة واحدة:
يستغرق توفير Cloud Shell والاتصال به بضع لحظات فقط.
يتم تحميل هذه الآلة الافتراضية مزوّدة بكل أدوات التطوير التي ستحتاج إليها. توفّر هذه الخدمة دليلًا رئيسيًا دائمًا بسعة 5 غيغابايت وتعمل في Google Cloud، ما يؤدي إلى تحسين أداء الشبكة والمصادقة بشكل كبير. يمكن إنجاز معظم العمل في هذا الدرس التطبيقي حول الترميز، إن لم يكن كله، باستخدام متصفّح أو جهاز Chromebook فقط.
بعد الاتصال بـ Cloud Shell، من المفترض أن يظهر لك أنّه تم إثبات هويتك وأنّه تم ضبط المشروع على رقم تعريف مشروعك.
- نفِّذ الأمر التالي في 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 Spanner
فعِّل Cloud Spanner API باستخدام gcloud CLI:
gcloud services enable spanner.googleapis.com
أنشئ مثيلاً من Cloud Spanner:
gcloud spanner instances create spanner-instance \ --config=regional-us-central1 \ --nodes=1 --description="A Spanner Instance"
أنشئ قاعدة بيانات داخل المثيل:
gcloud spanner databases create orders \ --instance=spanner-instance
أنشئ ملف schema.ddl لوصف مخطط البيانات:
cat << EOF > schema.ddl CREATE TABLE orders ( order_id STRING(36) NOT NULL, description STRING(255), creation_timestamp TIMESTAMP, ) PRIMARY KEY (order_id); CREATE TABLE order_items ( order_id STRING(36) NOT NULL, order_item_id STRING(36) NOT NULL, description STRING(255), quantity INT64, ) PRIMARY KEY (order_id, order_item_id), INTERLEAVE IN PARENT orders ON DELETE CASCADE; EOF
طبِّق المخطط على قاعدة بيانات Cloud Spanner:
gcloud spanner databases ddl update orders \ --instance=spanner-instance \ --ddl="$(<schema.ddl)"
4. إنشاء تطبيق Java جديد باستخدام Spring Boot
من بيئة Cloud Shell، استخدِم الأمر التالي لتهيئة تطبيق Spring Boot جديد وإعداده:
$ curl https://start.spring.io/starter.tgz \ -d packaging=jar \ -d dependencies=cloud-gcp,web,lombok \ -d baseDir=spanner-example \ -d type=maven-project \ -d bootVersion=3.2.6 | tar -xzvf - $ cd spanner-example
سيؤدي ذلك إلى إنشاء دليل spanner-example/ جديد يتضمّن مشروع Maven جديدًا، بالإضافة إلى pom.xml من Maven، وواجهة Maven، ونقطة دخول التطبيق.
في ملف pom.xml، أضِف أداة بدء Spring Data Cloud Spanner.
spanner-example/pom.xml
<project>
...
<dependencies>
...
<!-- Add Spring Cloud GCP Spanner Starter -->
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-data-spanner</artifactId>
</dependency>
...
</dependencies>
...
</project>
في ملف application.properties، اضبط معلومات ربط قاعدة بيانات Spanner:
spanner-example/src/main/resources/application.properties
spring.cloud.gcp.spanner.instance-id=spanner-instance spring.cloud.gcp.spanner.database=orders
تأكَّد من ضبط JAVA_HOME على الإصدار الصحيح:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/
أعِد إنشاء التطبيق للتأكّد من صحة إعدادات Maven:
./mvnw package
5- إنشاء الكيانات
باستخدام ميزة Spring Data Spanner المتوافقة مع Spring Cloud GCP، يمكنك بسهولة إنشاء عنصر Java وربطه بجدول Spanner باستخدام ORM، وذلك باستخدام Spring Data.
أولاً، أنشئ فئة "عنصر الطلب".
spanner-example/src/main/java/com/example/demo/OrderItem.java
package com.example.demo;
import com.google.cloud.spring.data.spanner.core.mapping.Column;
import com.google.cloud.spring.data.spanner.core.mapping.PrimaryKey;
import com.google.cloud.spring.data.spanner.core.mapping.Table;
@Table(name="order_items")
@Data
class OrderItem {
@PrimaryKey(keyOrder = 1)
@Column(name="order_id")
private String orderId;
@PrimaryKey(keyOrder = 2)
@Column(name="order_item_id")
private String orderItemId;
private String description;
private Long quantity;
}
بالنسبة إلى علاقات العنصر الرئيسي/العنصر الثانوي في Spanner، يجب استخدام مفتاح أساسي مركّب. في هذا المثال، المفتاح المركّب هو order_id وorder_item_id.
بعد ذلك، أنشئ فئة Order:
spanner-example/src/main/java/com/example/demo/Order.java
package com.example.demo;
import java.time.LocalDateTime;
import java.util.List;
import lombok.Data;
import com.google.cloud.spring.data.spanner.core.mapping.Column;
import com.google.cloud.spring.data.spanner.core.mapping.Interleaved;
import com.google.cloud.spring.data.spanner.core.mapping.PrimaryKey;
import com.google.cloud.spring.data.spanner.core.mapping.Table;
@Table(name="orders")
@Data
public class Order {
@PrimaryKey
@Column(name="order_id")
private String id;
private String description;
@Column(name="creation_timestamp")
private LocalDateTime timestamp;
@Interleaved
private List<OrderItem> items;
}
يستخدم هذا الصف التعليق التوضيحي @Interleaved لإنشاء علاقة بين عنصر واحد وعدة عناصر من "بنود الطلب".
6. إنشاء واجهة OrderRepository
أنشئ فئة OrderRepository تتضمّن المحتوى التالي:
spanner-example/src/main/java/com/example/demo/OrderRepository.java
package com.example.demo;
import com.google.cloud.spring.data.spanner.repository.SpannerRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface OrderRepository extends SpannerRepository<Order, String> {
}
توسّع الواجهة SpannerRepository<Order, String> حيث Order هو فئة النطاق وString هو نوع المفتاح الأساسي. ستوفّر Spring Data تلقائيًا إمكانية الوصول إلى عمليات الإنشاء والقراءة والتعديل والحذف من خلال هذه الواجهة، ولن تحتاج إلى إنشاء أي رموز إضافية.
7. إنشاء وحدة تحكّم REST للعمليات الأساسية
افتح فئة التطبيق الرئيسية DemoApplication وعدِّلها لتصبح على النحو التالي:
spanner-example/src/main/java/com/example/demo/DemoApplication.java
package com.example.demo;
import java.time.LocalDateTime;
import java.util.UUID;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@RestController
class OrderController {
private final OrderRepository orderRepository;
OrderController(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@GetMapping("/api/orders/{id}")
public Order getOrder(@PathVariable String id) {
return orderRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, id + " not found"));
}
@PostMapping("/api/orders")
public String createOrder(@RequestBody Order order) {
// Spanner currently does not auto generate IDs
// Generate UUID on new orders
order.setId(UUID.randomUUID().toString());
order.setTimestamp(LocalDateTime.now());
order.getItems().forEach(item -> {
// Assign parent ID, and also generate child ID
item.setOrderId(order.getId());
item.setOrderItemId(UUID.randomUUID().toString());
});
Order saved = orderRepository.save(order);
return saved.getId();
}
}
8. تشغيل التطبيق
أعِد إنشاء التطبيق وشغِّله.
./mvnw spring-boot:run
يجب أن يبدأ هذا الخادم بشكل صحيح وأن يستجيب على المنفذ 8080.
يمكنك نشر سجلّ طلب إلى نقطة النهاية:
curl -H"Content-Type: application/json" -d'{"description": "My orders", "items": [{"description": "Android Phone", "quantity": "1"}]}' \
http://localhost:8080/api/orders
يجب أن يردّ برقم تعريف الطلب UUID.
يمكنك بعد ذلك استرداد الطلب باستخدام UUID:
curl http://localhost:8080/api/orders/REPLACE_WITH_ORDER_UUID
للاطّلاع على طريقة تخزين البيانات في Cloud Spanner، انتقِل إلى Cloud Console ثم إلى Spanner → مثيل Spanner → قاعدة بيانات الطلبات → جدول الطلبات → البيانات.

9- تَنظيم
لإجراء عملية التنظيف، احذف مثيل Spanner حتى لا يتم تحصيل رسوم منك بعد الآن.
gcloud spanner instances delete spanner-instance -q
10. تهانينا!
في هذا الدرس التطبيقي حول الترميز، أنشأت تطبيقًا تفاعليًا لواجهة سطر الأوامر يمكنه تخزين البيانات واسترجاعها من Cloud Spanner.
مزيد من المعلومات
- Cloud Spanner: https://cloud.google.com/spanner/
- مشروع Spring على Google Cloud Platform: https://googlecloudplatform.github.io/spring-cloud-gcp/reference/html/
- مستودع Spring on GCP GitHub: https://github.com/spring-cloud/spring-cloud-gcp
- Java على Google Cloud Platform: https://cloud.google.com/java/
الترخيص
يخضع هذا العمل لترخيص المشاع الإبداعي مع نسب العمل إلى مؤلفه 2.0 Generic License.