Spanner 使用入门 (REST)


目标

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

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

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

费用

本教程使用 Spanner,它是 Google Cloud如需了解 Spanner 的使用费用,请参阅 定价

准备工作

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  5. Make sure that billing is enabled for your Google Cloud project.

进行 REST 调用的方式

您可以使用以下方式进行 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 请求字段。本主题中的大多数示例都提供了整个请求,而不是描述如何以交互方式将个别字段添加到请求中。

实例

首次使用 Spanner 时,您必须创建一个实例,实例是 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 列出您的数据库。

创建架构

使用 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 检索您的架构。

创建会话

在添加、更新、删除或查询数据之前,您必须先创建 session:代表与 Spanner 数据库服务。(如果您使用的是 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]
    

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

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

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

写入数据

您可以使用 Mutation 类型来写入数据。Mutation 是用于变更操作的容器。Mutation 表示插入、更新、删除等一系列操作, 以原子方式应用于 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 表,此操作需要更新您的数据库架构。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 列中的所有值,然后舍弃不符合条件的行。不过,执行全表扫描费用高昂,特别是对内含大量行的表来说更是如此。相反,如果对表创建二级索引,按非主键列进行搜索,则可以提高行检索速度。

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

添加二级索引后,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 列。这是因为 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"
      ]
    ]
    

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

后续步骤