אפליקציית Spring Spanner עם שירות Cloud Spanner

1. סקירה כללית

Cloud Spanner הוא מערכת RDBMS זמינה מאוד, בעלת יכולת הרחבה אופקית ופועלת במספר אזורים.במעבדת הקוד הזו נשתמש במופע הקטן ביותר של Cloud Spanner, אבל אל תשכחו לכבות אותו בסיום!

מה תלמדו

  • איך משתמשים ב-Cloud Spanner כדי לשמור ולאחזר נתונים באמצעות Spring Boot

הדרישות

  • פרויקט ב-Google Cloud Platform
  • דפדפן, כמו Chrome או Firefox

איך תשתמשו במדריך הזה?

רק לקרוא לקרוא ולבצע את התרגילים

איזה דירוג מגיע לדעתך לחוויית השימוש שלך בשירותים של Google Cloud Platform?

מתחילים ביניים מומחים

2. הגדרה ודרישות

הגדרת סביבה בקצב אישי

  1. נכנסים אל Cloud Console ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. (אם עדיין אין לכם חשבון Gmail או G Suite, אתם צריכים ליצור חשבון).

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

חשוב לזכור את מזהה הפרויקט, שהוא שם ייחודי בכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא יתאים לכם, מצטערים!). בהמשך ה-codelab הזה נתייחס אליו כאל PROJECT_ID.

  1. לאחר מכן, תצטרכו להפעיל את החיוב ב-Cloud Console כדי להשתמש במשאבים של Google Cloud.

העלות של התרגול הזה לא אמורה להיות גבוהה, ואולי אפילו לא תצטרכו לשלם בכלל. חשוב לפעול לפי ההוראות בקטע 'ניקוי' כדי להשבית את המשאבים, וכך לא תחויבו אחרי שתסיימו את המדריך הזה. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.

הפעלת Cloud Shell

  1. ב-Cloud Console, לוחצים על Activate Cloud Shell H7JlbhKGHITmsxhQIcLwoe5HXZMhDlYue4K-SPszMxUxDjIeWfOHBfxDHYpmLQTzUmQ7Xx8o6OJUlANnQF0iBuUyfp1RzVad_4nCa0Zz5LtwBlUZFXFCWFrmrWZLqg1MkZz2LdgUDQ.

zlNW0HehB_AFW1qZ4AyebSQUdWm95n7TbnOr7UVm3j9dFcg6oWApJRlC0jnU1Mvb-IQp-trP1Px8xKNwt6o3pP6fyih947sEhOFI4IRF0W7WZk6hFqZDUGXQQXrw21GuMm2ecHrbzQ

אם זו הפעם הראשונה שאתם מפעילים את Cloud Shell, יוצג לכם מסך ביניים (בחלק הנגלל) עם תיאור של Cloud Shell. במקרה כזה, לוחצים על המשך (והמסך הזה לא יוצג לכם יותר). כך נראה המסך החד-פעמי:

kEPbNAo_w5C_pi9QvhFwWwky1cX8hr_xEMGWySNIoMCdi-Djx9AQRqWn-__DmEpC7vKgUtl-feTcv-wBxJ8NwzzAp7mY65-fi2LJo4twUoewT1SUjd6Y3h81RG3rKIkqhoVlFR-G7w

הקצאת המשאבים והחיבור ל-Cloud Shell נמשכים רק כמה רגעים.

pTv5mEKzWMWp5VBrg2eGcuRPv9dLInPToS-mohlrqDASyYGWnZ_SwE-MzOWHe76ZdCSmw0kgWogSJv27lrQE8pvA5OD6P1I47nz8vrAdK7yR1NseZKJvcxAZrPb8wRxoqyTpD-gbhA

המכונה הווירטואלית הזו כוללת את כל הכלים שדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. אפשר לבצע את רוב העבודה ב-codelab הזה, אם לא את כולה, באמצעות דפדפן או Chromebook.

אחרי שמתחברים ל-Cloud Shell, אמור להופיע אימות שכבר בוצע ושהפרויקט כבר הוגדר לפי מזהה הפרויקט.

  1. מריצים את הפקודה הבאה ב-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 באמצעות ה-CLI של gcloud:

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 Wrapper ולנקודת כניסה לאפליקציה.

בקובץ pom.xml, מוסיפים את Spring Data Cloud Spanner starter.

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 ומיפוי ORM אידיומטי לטבלת Spanner באמצעות 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.

בשלב הבא, יוצרים מחלקה של הזמנה:

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;
}

במחלקת ה-class הזו נעשה שימוש בהערה @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 יספק באופן אוטומטי גישת CRUD דרך הממשק הזה, ולא תצטרכו ליצור קוד נוסף.

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 Instance → order database → orders table → Data.

780f4947e4a864f6.png

9. הסרת המשאבים

כדי לנקות, מוחקים את מופע Spanner כדי שלא יחויבו יותר חיובים!

gcloud spanner instances delete spanner-instance -q

10. מעולה!

ב-codelab הזה יצרתם אפליקציית CLI אינטראקטיבית שיכולה לאחסן נתונים ב-Cloud Spanner ולאחזר אותם.

מידע נוסף

רישיון

עבודה זו מורשית תחת רישיון Creative Commons שמותנה בייחוס 2.0 כללי.