1. 總覽
Cloud Spanner 是高可用性、可水平擴充的多區域 RDBMS。本程式碼研究室將使用最小的 Cloud Spanner 執行個體,但別忘了在完成後關閉執行個體!
課程內容
- 如何使用 Spring Boot 搭配 Cloud Spanner 儲存及擷取資料
軟硬體需求
您會如何使用本教學課程?
您對使用 Google Cloud Platform 服務的體驗有何評價?
2. 設定和需求
自修實驗室環境設定
請記住專案 ID,這是所有 Google Cloud 專案中不重複的名稱 (上述名稱已遭占用,因此不適用於您,抱歉!)。本程式碼研究室稍後會將其稱為 PROJECT_ID。
- 接著,您必須在 Cloud 控制台中啟用帳單,才能使用 Google Cloud 資源。
完成本程式碼研究室的費用應該不高,甚至完全免費。請務必按照「清除」部分的指示操作,瞭解如何停用資源,避免在本教學課程結束後繼續產生帳單費用。Google Cloud 新使用者可參加價值$300 美元的免費試用計畫。
啟用 Cloud Shell
- 在 Cloud 控制台,點選「啟用 Cloud Shell」 圖示
。
如果您是首次啟動 Cloud Shell,系統會顯示中繼畫面 (摺疊式螢幕下方),說明這個指令列環境。點選「繼續」後,這則訊息日後就不會再出現。以下是這個初次畫面的樣子:
佈建並連至 Cloud Shell 預計只需要幾分鐘。
這部虛擬機器搭載各種您需要的開發工具,並提供永久的 5GB 主目錄,而且可在 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 Spanner
使用 gcloud CLI 啟用 Cloud Spanner API:
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. 啟動新的 Spring Boot Java 應用程式
在 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 專案,以及 Maven 的 pom.xml、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 Cloud GCP 的 Spring Data Spanner 支援功能,您可以使用 Spring Data 輕鬆建立 Java 物件,以及對應至 Spanner 資料表的慣用 ORM。
首先,請建立 Order Item 類別。
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 會透過這個介面自動提供 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。
您可以將 Order 記錄發布至端點:
curl -H"Content-Type: application/json" -d'{"description": "My orders", "items": [{"description": "Android Phone", "quantity": "1"}]}' \
http://localhost:8080/api/orders
並回覆訂單的 UUID。
接著,您可以使用 UUID 擷取 Order:
curl http://localhost:8080/api/orders/REPLACE_WITH_ORDER_UUID
如要查看資料在 Cloud Spanner 中的儲存方式,請前往 Cloud 控制台,然後依序點選「Spanner」→「Spanner 執行個體」→「order 資料庫」→「orders 資料表」→「資料」。

9. 清除所用資源
如要清除資源,請刪除 Spanner 執行個體,以免繼續產生費用!
gcloud spanner instances delete spanner-instance -q
10. 恭喜!
在本程式碼研究室中,您已建立互動式 CLI 應用程式,可儲存及擷取 Cloud Spanner 中的資料!
瞭解詳情
- Cloud Spanner:https://cloud.google.com/spanner/
- GCP 上的 Spring 專案:https://googlecloudplatform.github.io/spring-cloud-gcp/reference/html/
- GCP 上的 Spring GitHub 存放區:https://github.com/spring-cloud/spring-cloud-gcp
- 在 Google Cloud Platform 上使用 Java:https://cloud.google.com/java/
授權
這項內容採用的授權為 Creative Commons 姓名標示 2.0 通用授權。