แอปพลิเคชัน Spring Boot ที่มี 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

การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี ตรวจสอบว่าคุณได้ทำตามวิธีการใน "การล้างข้อมูล" ซึ่งจะแนะนำคุณเกี่ยวกับวิธีปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD

เปิดใช้งาน Cloud Shell

  1. คลิกเปิดใช้งาน Cloud Shell กริ๊งๆๆๆ จาก Cloud Console

zlNW0HehB_AFW1qZ4AyebSQUdWm95n7TbnOr7UVm3j9dFcg6oWApJRlC0jnU1Mvb-IQp-trP1Px8xKNwt6o3pP6fyih947sEhOFI4IRF0W7WZk6hFqZDUGXQQXrw21GuMm2ecHrbzQ

หากคุณไม่เคยเริ่มต้นใช้งาน Cloud Shell มาก่อน คุณจะเห็นหน้าจอตรงกลาง (ครึ่งหน้าล่าง) ซึ่งอธิบายว่านี่คืออะไร หากเป็นเช่นนั้น ให้คลิกดำเนินการต่อ (คุณจะไม่เห็นการดำเนินการนี้อีก) หน้าจอแบบครั้งเดียวมีลักษณะดังนี้

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

การจัดสรรและเชื่อมต่อกับ Cloud Shell ใช้เวลาเพียงไม่กี่นาที

pTv5mEKzWMWp5VBrg2eGcuRPv9dLInPToS-mohlrqDASyYGWnZ_SwE-MzOWHe76ZdCSmw0kgWogSJv27lrQE8pvA5OD6P1I47nz8vrAdK7yR1NseZKJvcxAZrPb8wRxoqyTpD-gbhA

เครื่องเสมือนนี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ทำงานอย่างต่อเนื่องใน 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 โดยใช้ 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, Wrapper ของ 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 และการแมป ORM แบบระบุตัวตนกับตาราง Spanner ได้อย่างง่ายดายโดยใช้ข้อมูล Spring

ก่อนอื่นให้สร้างคลาส "สินค้าในคำสั่งซื้อ"

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

คลาสนี้ใช้คำอธิบายประกอบ @Interleaved เพื่อสร้างความสัมพันธ์แบบ 1 ต่อหลายรายการกับรายการในคำสั่งซื้อ

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 → ฐานข้อมูลคำสั่งซื้อ → ตารางคำสั่งซื้อ → ข้อมูล

780f4947e4a864f6.png

9. ล้างข้อมูล

หากต้องการล้างข้อมูล ให้ลบอินสแตนซ์ Spanner เพื่อไม่ให้มีการเรียกเก็บเงินอีก

gcloud spanner instances delete spanner-instance -q

10. ยินดีด้วย

ใน Codelab นี้ คุณได้สร้างแอปพลิเคชัน CLI แบบอินเทอร์แอกทีฟที่สามารถจัดเก็บและเรียกข้อมูลจาก Cloud Spanner

ดูข้อมูลเพิ่มเติม

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้ใบอนุญาตทั่วไปครีเอทีฟคอมมอนส์แบบระบุแหล่งที่มา 2.0