1. 概览
Cloud Spanner 是一个可用性高、可横向扩缩的多区域 RDBMS。此 Codelab 将使用 Cloud Spanner 的最小实例,但请务必在完成后关闭它!
学习内容
- 如何使用 Cloud Spanner 通过 Spring Boot 保存和检索数据
所需条件
您打算如何使用本教程?
您如何评价自己在使用 Google Cloud Platform 服务方面的经验水平?
<ph type="x-smartling-placeholder">2. 设置和要求
自定进度的环境设置
请记住项目 ID,它在所有 Google Cloud 项目中都是唯一的名称(上述名称已被占用,您无法使用,抱歉!)。它稍后将在此 Codelab 中被称为 PROJECT_ID
。
- 接下来,您需要在 Cloud 控制台中启用结算功能,才能使用 Google Cloud 资源。
运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。请务必按照“清理”部分部分,其中会指导您如何关停资源,以免产生超出本教程范围的结算费用。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。
激活 Cloud Shell
- 在 Cloud Console 中,点击激活 Cloud Shell。
如果您以前从未启动过 Cloud Shell,将看到一个中间屏幕(在折叠下面),描述它是什么。如果是这种情况,请点击继续(您将永远不会再看到它)。一次性屏幕如下所示:
预配和连接到 Cloud Shell 只需花几分钟时间。
这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证。只需使用一个浏览器或 Google Chromebook 即可完成本 Codelab 中的大部分(甚至全部)工作。
在连接到 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
这将使用一个新的 Maven 项目、Maven 的 pom.xml
(一个 Maven 封装容器)和一个应用入口点来创建一个新的 spanner-example/
目录。
在 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 支持,您可以轻松创建 Java 对象,并使用 Spring Data 轻松创建到 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。
您可以将订单记录发布到端点:
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. 恭喜!
在此 Codelab 中,您创建了一个交互式 CLI 应用,该应用可以在 Cloud Spanner 中存储和检索数据!
了解详情
- Cloud Spanner:https://cloud.google.com/spanner/
- GCP 项目的 Spring:https://googlecloudplatform.github.io/spring-cloud-gcp/reference/html/
- GCP GitHub 代码库上的 Spring:https://github.com/spring-cloud/spring-cloud-gcp
- Google Cloud Platform 上的 Java:https://cloud.google.com/java/
许可
此作品已获得 Creative Commons Attribution 2.0 通用许可授权。