Cloud Spanner 使用入门 (REST)

目标

本教程将介绍如何使用基于 REST 的 Cloud Spanner API 完成以下步骤:

  • 创建 Cloud Spanner 实例和数据库。
  • 写入、读取数据库中的数据和对数据执行 SQL 查询。
  • 更新数据库架构。
  • 向数据库添加二级索引。
  • 使用索引来读取数据和对数据执行 SQL 查询。
  • 使用只读事务检索数据。

如果您想使用 Cloud Spanner 客户端库,而不使用 REST API,请参阅教程

费用

本教程使用 Cloud Spanner,它是 Google Cloud 的收费组件。如需了解使用 Cloud Spanner 的费用,请参阅价格

准备工作

  1. 登录您的 Google 帐号。

    如果您还没有 Google 帐号,请注册新帐号

  2. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到项目选择器页面

  3. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

进行 REST 调用的方式

您可以使用以下方式进行 Cloud Spanner REST 调用:

本页面使用的约定

  • 这些示例使用 [PROJECT_ID] 作为 Google Cloud 项目 ID。请将 [PROJECT_ID] 替换为您的 Google Cloud 项目 ID。(请勿在项目 ID 中包含 []。)

  • 这些示例创建并使用 test-instance 的实例 ID。如果您未使用 test-instance,请替换您的实例 ID。

  • 这些示例创建并使用 example-db 的数据库 ID。如果您未使用 example-db,请替换您的数据库 ID。

  • 这些示例使用 [SESSION] 作为会话名称的一部分。请将 [SESSION] 替换成您在创建会话时收到的值。(请勿在会话名称中包含 []。)

  • 这些示例使用 [TRANSACTION_ID] 的事务 ID。请将 [TRANSACTION_ID] 替换成您在创建事务时收到的值。(请勿在事务 ID 中包含 []。)

  • Try-It! 功能支持以交互方式添加个别 HTTP 请求字段。本主题中的大多数示例都提供了整个请求,而不是描述如何以交互方式将个别字段添加到请求中。

实例

在首次使用 Cloud Spanner 时,必须创建一个实例,用于分配供 Cloud Spanner 数据库使用的资源。创建实例时,您可以选择数据的存储位置以及数据使用的节点数量。

列出实例配置

在创建实例时,您可以指定一个实例配置,用于定义该实例中数据库的地理位置和复制。您可以选择单区域配置以将数据存储在单个区域中,也可以选择多区域配置以将数据分布到多个区域。如需了解详情,请参阅实例

使用 projects.instanceConfigs.list 确定哪些配置可用于您的 Google Cloud 项目。

  1. 点击 projects.instanceConfigs.list
  2. 对于 parent,输入:

    projects/[PROJECT_ID]
    
  3. 点击 Execute。响应中会显示可用的实例配置。以下是一个示例响应(您的项目可能会采用不同的实例配置):

    {
      "instanceConfigs": [
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-asia-south1",
          "displayName": "asia-south1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-asia-east1",
          "displayName": "asia-east1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-asia-northeast1",
          "displayName": "asia-northeast1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-europe-west1",
          "displayName": "europe-west1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-us-east4",
          "displayName": "us-east4"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-us-central1",
          "displayName": "us-central1"
        }
      ]
    }
    

创建实例时,您可以使用其中一个实例配置的 name 值。

创建实例

  1. 点击 projects.instances.create
  2. 对于 parent,输入:

    projects/[PROJECT_ID]
    
  3. 点击 Add request body parameters 并选择 instance

  4. 点击 instance 提示气泡以查看可能的字段。为以下字段添加值:

    1. nodeCount:输入 1
    2. config:输入在列出实例配置时返回的其中一个区域实例配置的 name 值。
    3. displayName:输入 Test Instance
  5. 点击 instance 右括号后面的提示气泡,然后选择 instanceId

  6. 对于 instanceId,输入 test-instance
    您的 Try It! 实例创建页面现在应该如下所示:

    实例创建界面屏幕截图

  7. 点击执行。该响应会返回一个长时间运行的操作,您可以查询该操作以检查其状态。

您可以使用 projects.instances.list 列出您的实例。

创建数据库

创建一个名为 example-db 的数据库。

  1. 点击 projects.instances.databases.create
  2. 对于 parent,输入:

    projects/[PROJECT_ID]/instances/test-instance
    
  3. 点击 Add request body parameters 并选择 createStatement

  4. 对于 createStatement,输入:

    CREATE DATABASE `example-db`
    

    (数据库名称 example-db 包含一个连字符,所以必须用反引号 (`) 括起来)。

  5. 点击 Execute。该响应会返回一个长时间运行的操作,您可以查询该操作以检查其状态。

您可以使用 projects.instances.databases.list 列出您的数据库。

创建架构

使用 Cloud Spanner 的数据定义语言 (DDL) 来创建、修改或删除表,以及创建或删除索引。

  1. 点击 projects.instances.databases.updateDdl
  2. 对于 database,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. 对于 Request body,使用以下内容:

    {
      "statements": [
        "CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), SingerInfo BYTES(MAX) ) PRIMARY KEY (SingerId)",
        "CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX)) PRIMARY KEY (SingerId, AlbumId), INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
      ]
    }
    

    statements 数组包含用于定义架构的 DDL 语句。

  4. 点击 Execute。该响应会返回一个长时间运行的操作,您可以查询该操作以检查其状态。

该架构为一个基本的音乐应用定义了两个表:SingersAlbums。本页面会一直用到这两个表。请查看示例架构(如果您还没有查看)。

您可以使用 projects.instances.databases.getDdl 检索您的架构。

创建会话

在添加、更新、删除或查询数据之前,您必须创建一个会话,该会话代表与 Cloud Spanner 数据库服务之间的一个通信渠道。(如果您使用的是 Cloud Spanner 客户端库,则不需要直接使用会话,因为客户端库会代表您管理会话。)

  1. 点击 projects.instances.databases.sessions.create
  2. 对于 database,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. 点击 Execute

  4. 响应会显示您创建的会话,形式为

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    在读取或写入数据库时,您将使用此会话。

会话设计为长期有效。Cloud Spanner 数据库服务可以在会话空闲超过一小时后删除会话。尝试使用已删除的会话会导致 NOT_FOUND 错误。如果遇到此错误,请创建并使用新会话。您可以使用 projects.instances.databases.sessions.get 查看会话是否仍处于活动状态。如需了解相关信息,请参阅使空闲会话保持活动状态

下一步是将数据写入数据库。

写入数据

您可以使用 Mutation 类型来写入数据。Mutation 是用于变更操作的容器。Mutation 代表插入、更新、删除及一系列其他操作,这些操作可以原子方式应用于 Cloud Spanner 数据库中的不同行和表。

  1. 点击 projects.instances.databases.sessions.commit
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "singleUseTransaction": {
        "readWrite": {}
      },
      "mutations": [
        {
          "insertOrUpdate": {
            "table": "Singers",
            "columns": [
              "SingerId",
              "FirstName",
              "LastName"
            ],
            "values": [
              [
                "1",
                "Marc",
                "Richards"
              ],
              [
                "2",
                "Catalina",
                "Smith"
              ],
              [
                "3",
                "Alice",
                "Trentor"
              ],
              [
                "4",
                "Lea",
                "Martin"
              ],
              [
                "5",
                "David",
                "Lomond"
              ]
            ]
          }
        },
        {
          "insertOrUpdate": {
            "table": "Albums",
            "columns": [
              "SingerId",
              "AlbumId",
              "AlbumTitle"
            ],
            "values": [
              [
                "1",
                "1",
                "Total Junk"
              ],
              [
                "1",
                "2",
                "Go, Go, Go"
              ],
              [
                "2",
                "1",
                "Green"
              ],
              [
                "2",
                "2",
                "Forever Hold Your Peace"
              ],
              [
                "2",
                "3",
                "Terrified"
              ]
            ]
          }
        }
      ]
    }
    
  4. 点击 Execute。该响应会显示提交时间戳。

本示例使用了 insertOrUpdateMutations 的其他操作包括 insertupdatereplacedelete

如需了解如何对数据类型进行编码,请参阅 TypeCode

使用 SQL 查询数据

  1. 点击 projects.instances.databases.sessions.executeSql
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "sql": "SELECT SingerId, AlbumId, AlbumTitle FROM Albums"
    }
    
  4. 点击 Execute。该响应会显示查询结果。

使用读取 API 读取数据

  1. 点击 projects.instances.databases.sessions.read
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "table": "Albums",
      "columns": [
        "SingerId",
        "AlbumId",
        "AlbumTitle"
      ],
      "keySet": {
        "all": true
      }
    }
    
  4. 点击 Execute。该响应会显示读取结果。

更新数据库架构

假设您需要将名为 MarketingBudget 的新列添加到 Albums 表,此操作需要更新您的数据库架构。Cloud Spanner 支持在数据库继续处理流量的同时,对数据库进行架构更新。架构更新不需要使数据库离线,并且不会锁定整个表或列;在架构更新期间,您可以继续将数据写入数据库。

添加列

  1. 点击 projects.instances.databases.updateDdl
  2. 对于 database,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. 对于 Request body,使用以下内容:

    {
      "statements": [
        "ALTER TABLE Albums ADD COLUMN MarketingBudget INT64"
      ]
    }
    

    statements 数组包含用于定义架构的 DDL 语句。

  4. 点击执行。即使在 REST 调用返回响应之后,该操作也可能需要几分钟才能完成。该响应会返回一个长时间运行的操作,您可以查询该操作以检查其状态。

将数据写入新列

以下代码可将数据写入新列。对于键分别为 Albums(1, 1)Albums(2, 2) 的行,该代码会将 MarketingBudget 分别设置为 100000500000

  1. 点击 projects.instances.databases.sessions.commit
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "singleUseTransaction": {
        "readWrite": {}
      },
      "mutations": [
        {
          "update": {
            "table": "Albums",
            "columns": [
              "SingerId",
              "AlbumId",
              "MarketingBudget"
            ],
            "values": [
              [
                "1",
                "1",
                "100000"
              ],
              [
                "2",
                "2",
                "500000"
              ]
            ]
          }
        }
      ]
    }
    
  4. 点击 Execute。该响应会显示提交时间戳。

您还可以执行 SQL 查询或读取调用来获取刚才写入的值。

以下是执行查询的方法:

  1. 点击 projects.instances.databases.sessions.executeSql
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "sql": "SELECT SingerId, AlbumId, MarketingBudget FROM Albums"
    }
    
  4. 点击 Execute。作为响应的一部分,您应该可以看到包含更新后的 MarketingBudget 值的两行:

    "rows": [
      [
        "1",
        "1",
        "100000"
      ],
      [
        "1",
        "2",
        null
      ],
      [
        "2",
        "1",
        null
      ],
      [
        "2",
        "2",
        "500000"
      ],
      [
        "2",
        "3",
        null
      ]
    ]
    

使用二级索引

假设您想要提取 Albums 表中 AlbumTitle 值在特定范围内的所有行。您可以使用 SQL 语句或读取调用读取 AlbumTitle 列中的所有值,然后舍弃不符合条件的行。不过,执行全表扫描费用高昂,特别是对内含大量行的表来说更是如此。相反,如果对表创建二级索引,按非主键列进行搜索,则可以提高行检索速度。

向现有表添加二级索引需要更新架构。与其他架构更新一样,Cloud Spanner 支持在数据库继续处理流量的同时添加索引。Cloud Spanner 会使用您的现有数据自动回填索引。回填可能需要几分钟时间才能完成,但在此过程中,您无需使数据库离线,也无需避免写入特定的表或列。如需了解详情,请参阅索引回填

添加二级索引后,Cloud Spanner 会自动使用该索引进行 SQL 查询,使用该索引后,查询运行速度可能会提高。如果使用读取接口,则必须指定要使用的索引。

添加二级索引

您可以使用 updateDdl 添加索引。

  1. 点击 projects.instances.databases.updateDdl
  2. 对于 database,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. 对于 Request body,使用以下内容:

    {
      "statements": [
        "CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)"
      ]
    }
    
  4. 点击 Execute。即使在 REST 调用返回响应之后,该操作也可能需要几分钟才能完成。该响应会返回一个长时间运行的操作,您可以查询该操作以检查其状态。

使用索引进行查询

  1. 点击 projects.instances.databases.sessions.executeSql
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "sql": "SELECT AlbumId, AlbumTitle, MarketingBudget FROM Albums WHERE AlbumTitle >= 'Aardvark' AND AlbumTitle < 'Goo'"
    }
    
  4. 点击 Execute。作为响应的一部分,您应该可以看到以下几行:

    "rows": [
      [
        "2",
        "Go, Go, Go",
        null
      ],
      [
        "2",
        "Forever Hold Your Peace",
        "500000"
      ]
    ]
    

使用索引进行读取

  1. 点击 projects.instances.databases.sessions.read
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "table": "Albums",
      "columns": [
        "AlbumId",
        "AlbumTitle"
      ],
      "keySet": {
        "all": true
      },
      "index": "AlbumsByAlbumTitle"
    }
    
  4. 点击 Execute。作为响应的一部分,您应该可以看到以下几行:

    "rows": [
      [
        "2",
        "Forever Hold Your Peace"
      ],
      [
        "2",
        "Go, Go, Go"
      ],
      [
        "1",
        "Green"
      ],
      [
        "3",
        "Terrified"
      ],
      [
        "1",
        "Total Junk"
      ]
    ]
    

添加带 STORING 子句的索引

您可能已经注意到,上面的读取示例不包括读取 MarketingBudget 列。这是因为,Cloud Spanner 的读取接口不支持将索引与数据表联接起来查找未存储在索引中的值。

请创建 AlbumsByAlbumTitle 的备用定义,以将 MarketingBudget 的副本存储到索引中。

您可以使用 updateDdl 添加 STORING 索引。

  1. 点击 projects.instances.databases.updateDdl
  2. 对于 database,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. 对于 Request body,使用以下内容:

    {
      "statements": [
        "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget)"
      ]
    }
    
  4. 点击 Execute。即使在 REST 调用返回响应之后,该操作也可能需要几分钟才能完成。该响应会返回一个长时间运行的操作,您可以查询该操作以检查其状态。

现在,当您执行读取操作时便可从 AlbumsByAlbumTitle2 索引中提取所有 AlbumIdAlbumTitleMarketingBudget 列:

  1. 点击 projects.instances.databases.sessions.read
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "table": "Albums",
      "columns": [
        "AlbumId",
        "AlbumTitle",
        "MarketingBudget"
      ],
      "keySet": {
        "all": true
      },
      "index": "AlbumsByAlbumTitle2"
    }
    
  4. 点击 Execute。作为响应的一部分,您应该可以看到以下几行:

    "rows": [
      [
        "2",
        "Forever Hold Your Peace",
        "500000"
      ],
      [
        "2",
        "Go, Go, Go",
        null
      ],
      [
        "1",
        "Green",
        null
      ],
      [
        "3",
        "Terrified",
        null
      ],
      [
        "1",
        "Total Junk",
        "100000"
      ]
    ]
    

使用只读事务检索数据

假设您要在同一时间戳执行多个读取操作。只读事务会观察事务提交记录的一致前缀,以便您的应用始终获得一致的数据。

创建只读事务

  1. 点击 projects.instances.databases.sessions.beginTransaction
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    
  3. 对于 Request Body,使用以下内容:

    {
      "options": {
        "readOnly": {}
      }
    }
    
  4. 点击 Execute

  5. 该响应会显示您创建的事务的 ID。

现在您可以使用只读事务以一致的时间戳检索数据,即使自创建只读事务后数据已更改。

使用只读事务运行查询

  1. 点击 projects.instances.databases.sessions.executeSql
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "sql": "SELECT SingerId, AlbumId, AlbumTitle FROM Albums",
      "transaction": {
        "id": "[TRANSACTION_ID]"
      }
    }
    
  4. 点击 Execute。您应该会在响应中看到与以下内容类似的行:

    "rows": [
      [
        "2",
        "2",
        "Forever Hold Your Peace"
      ],
      [
        "1",
        "2",
        "Go, Go, Go"
      ],
      [
        "2",
        "1",
        "Green"
      ],
      [
        "2",
        "3",
        "Terrified"
      ],
      [
        "1",
        "1",
        "Total Junk"
      ]
    ]
    

使用只读事务进行读取

  1. 点击 projects.instances.databases.sessions.read
  2. 对于 session,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (您在创建会话时会收到此值。)

  3. 对于 Request body,使用以下内容:

    {
      "table": "Albums",
      "columns": [
        "SingerId",
        "AlbumId",
        "AlbumTitle"
      ],
      "keySet": {
        "all": true
      },
      "transaction": {
        "id": "[TRANSACTION_ID]"
      }
    }
    
  4. 点击 Execute。您应该会在响应中看到与以下内容类似的行:

    "rows": [
      [
        "1",
        "1",
        "Total Junk"
      ],
      [
        "1",
        "2",
        "Go, Go, Go"
      ],
      [
        "2",
        "1",
        "Green"
      ],
      [
        "2",
        "2",
        "Forever Hold Your Peace"
      ],
      [
        "2",
        "3",
        "Terrified"
      ]
    ]
    

Cloud Spanner 还支持读写事务,该事务可在单个逻辑时间点以原子方式执行一组读写操作。如需了解详情,请参阅读写事务。(Try-It! 功能不适合演示读写事务。)

清理

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生额外费用,请删除数据库和您创建的实例。

删除数据库

  1. 点击 projects.instances.databases.dropDatabase
  2. 对于 name,输入:

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. 点击 Execute

删除实例

  1. 点击 projects.instances.delete
  2. 对于 name,输入:

    projects/[PROJECT_ID]/instances/test-instance
    
  3. 点击 Execute

后续步骤