Introdução ao Spanner em PHP


Objetivos

Este tutorial explica os seguintes passos através da biblioteca de cliente do Spanner para PHP:

  • Crie uma instância e uma base de dados do Spanner.
  • Escrever, ler e executar consultas SQL em dados na base de dados.
  • Atualize o esquema da base de dados.
  • Atualize os dados através de uma transação de leitura/escrita.
  • Adicione um índice secundário à base de dados.
  • Use o índice para ler e executar consultas SQL em dados.
  • Recuperar dados através de uma transação só de leitura.

Custos

Este tutorial usa o Spanner, que é um componente faturável do Google Cloud. Para obter informações sobre o custo de utilização do Spanner, consulte a secção Preços.

Antes de começar

Conclua os passos descritos em Configuração, que abrangem a criação e a definição de um projeto Google Cloud predefinido, a ativação da faturação, a ativação da API Cloud Spanner e a configuração do OAuth 2.0 para obter credenciais de autenticação para usar a API Cloud Spanner.

Em particular, certifique-se de que executa gcloud auth application-default login para configurar o seu ambiente de desenvolvimento local com credenciais de autenticação.

Prepare o seu ambiente PHP local

  1. Siga os passos em Contas de serviço para configurar uma conta de serviço como as suas credenciais predefinidas da aplicação. Após seguir estes passos, deve obter um ficheiro de chave da conta de serviço (em JSON) e uma variável de ambiente GOOGLE_APPLICATION_CREDENTIALS que lhe permite autenticar-se na API Spanner.

  2. Instale o seguinte no seu computador de desenvolvimento, se ainda não estiver instalado:

  3. Clone o repositório da app de exemplo para a sua máquina local:

    git clone https://github.com/GoogleCloudPlatform/php-docs-samples
    

    Em alternativa, pode transferir o exemplo como um ficheiro ZIP e extraí-lo.

  4. Altere para o diretório que contém o código de exemplo do Spanner:

    cd php-docs-samples/spanner
    
  5. Instalar dependências:

    composer install
    

    Isto instala a biblioteca cliente do Spanner para PHP, que pode adicionar a qualquer projeto executando composer require google/cloud-spanner.

Crie uma instância

Quando usa o Spanner pela primeira vez, tem de criar uma instância, que é uma atribuição de recursos usados pelas bases de dados do Spanner. Quando cria uma instância, escolhe uma configuração da instância, que determina onde os seus dados são armazenados, bem como o número de nós a usar, o que determina a quantidade de recursos de publicação e armazenamento na sua instância.

Consulte o artigo Crie uma instância para saber como criar uma instância do Spanner através de qualquer um dos seguintes métodos. Pode dar o nome test-instance à sua instância para a usar com outros tópicos neste documento que façam referência a uma instância com o nome test-instance.

  • A CLI do Google Cloud
  • A Google Cloud consola
  • Uma biblioteca cliente (C++, C#, Go, Java, Node.js, PHP, Python ou Ruby)

Explore ficheiros de exemplo

O repositório de exemplos contém um exemplo que mostra como usar o Spanner com PHP.

Consulte as funções em src/create_database.php e src/add_column.php, que mostram como criar uma base de dados e modificar um esquema de base de dados. Os dados usam o esquema de exemplo apresentado na página Esquema e modelo de dados.

Crie uma base de dados

GoogleSQL

php src/create_database.php test-instance example-db

PostgreSQL

php src/pg_create_database.php test-instance example-db

Deve ver:

Created database example-db on instance test-instance
O código seguinte cria uma base de dados e duas tabelas na base de dados.

GoogleSQL

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CreateDatabaseRequest;

/**
 * Creates a database and tables for sample data.
 * Example:
 * ```
 * create_database($instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function create_database(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $instance = $databaseAdminClient->instanceName($projectId, $instanceId);

    $operation = $databaseAdminClient->createDatabase(
        new CreateDatabaseRequest([
            'parent' => $instance,
            'create_statement' => sprintf('CREATE DATABASE `%s`', $databaseId),
            'extra_statements' => [
                'CREATE TABLE Singers (' .
                'SingerId     INT64 NOT NULL,' .
                'FirstName    STRING(1024),' .
                'LastName     STRING(1024),' .
                'SingerInfo   BYTES(MAX),' .
                'FullName     STRING(2048) AS' .
                '(ARRAY_TO_STRING([FirstName, LastName], " ")) STORED' .
                ') 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'
            ]
        ])
    );

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    printf('Created database %s on instance %s' . PHP_EOL,
        $databaseId, $instanceId);
}

PostgreSQL

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CreateDatabaseRequest;
use Google\Cloud\Spanner\Admin\Database\V1\DatabaseDialect;
use Google\Cloud\Spanner\Admin\Database\V1\GetDatabaseRequest;
use Google\Cloud\Spanner\Admin\Database\V1\UpdateDatabaseDdlRequest;

/**
 * Creates a database that uses Postgres dialect
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function pg_create_database(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $instance = $databaseAdminClient->instanceName($projectId, $instanceId);
    $databaseName = $databaseAdminClient->databaseName($projectId, $instanceId, $databaseId);

    $table1Query = 'CREATE TABLE Singers (
        SingerId   bigint NOT NULL PRIMARY KEY,
        FirstName  varchar(1024),
        LastName   varchar(1024),
        SingerInfo bytea,
        FullName character varying(2048) GENERATED
        ALWAYS AS (FirstName || \' \' || LastName) STORED
    )';
    $table2Query = 'CREATE TABLE Albums (
        AlbumId      bigint NOT NULL,
        SingerId     bigint NOT NULL REFERENCES Singers (SingerId),
        AlbumTitle   text,
        PRIMARY KEY(SingerId, AlbumId)
    )';

    $operation = $databaseAdminClient->createDatabase(
        new CreateDatabaseRequest([
            'parent' => $instance,
            'create_statement' => sprintf('CREATE DATABASE "%s"', $databaseId),
            'extra_statements' => [],
            'database_dialect' => DatabaseDialect::POSTGRESQL
        ])
    );

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => [$table1Query, $table2Query]
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);
    $operation->pollUntilComplete();

    $database = $databaseAdminClient->getDatabase(
        new GetDatabaseRequest(['name' => $databaseAdminClient->databaseName($projectId, $instanceId, $databaseId)])
    );
    $dialect = DatabaseDialect::name($database->getDatabaseDialect());

    printf('Created database %s with dialect %s on instance %s' . PHP_EOL,
        $databaseId, $dialect, $instanceId);
}

O passo seguinte é escrever dados na sua base de dados.

Crie um cliente de base de dados

Para fazer leituras e escritas, tem de obter uma instância de Google\Cloud\Spanner\Database.

# Includes the autoloader for libraries installed with composer
require __DIR__ . '/vendor/autoload.php';

# Imports the Google Cloud client library
use Google\Cloud\Spanner\SpannerClient;

# Your Google Cloud Platform project ID
$projectId = 'YOUR_PROJECT_ID';

# Instantiates a client
$spanner = new SpannerClient([
    'projectId' => $projectId
]);

# Your Cloud Spanner instance ID.
$instanceId = 'your-instance-id';

# Get a Cloud Spanner instance by ID.
$instance = $spanner->instance($instanceId);

# Your Cloud Spanner database ID.
$databaseId = 'your-database-id';

# Get a Cloud Spanner database by ID.
$database = $instance->database($databaseId);

# Execute a simple SQL statement.
$results = $database->execute('SELECT "Hello World" as test');

foreach ($results as $row) {
    print($row['test'] . PHP_EOL);
}

Pode pensar num Database como uma ligação de base de dados: todas as suas interações com o Spanner têm de passar por um Database. Normalmente, cria um Database quando a sua aplicação é iniciada e, em seguida, volta a usar esse Database para ler, escrever e executar transações. Cada cliente usa recursos no Spanner.

Se criar vários clientes na mesma app, deve chamar Database::close para limpar os recursos do cliente, incluindo as ligações de rede, assim que deixar de ser necessário.

Leia mais na Database referência.

Escreva dados com DML

Pode inserir dados através da linguagem de manipulação de dados (DML) numa transação de leitura/escrita.

Usa o método executeUpdate() para executar uma declaração DML.

use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Transaction;

/**
 * Inserts sample data into the given database with a DML statement.
 *
 * The database and table must already exist and can be created using
 * `create_database`.
 * Example:
 * ```
 * insert_data($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function write_data_with_dml(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $database->runTransaction(function (Transaction $t) {
        $rowCount = $t->executeUpdate(
            'INSERT Singers (SingerId, FirstName, LastName) VALUES '
            . "(12, 'Melissa', 'Garcia'), "
            . "(13, 'Russell', 'Morales'), "
            . "(14, 'Jacqueline', 'Long'), "
            . "(15, 'Dylan', 'Shaw')");
        $t->commit();
        printf('Inserted %d row(s).' . PHP_EOL, $rowCount);
    });
}

Execute o ficheiro de exemplo src/write_data_with_dml.php.

php src/write_data_with_dml.php test-instance example-db

Deve ver:

Inserted 4 row(s).

Escreva dados com mutações

Também pode inserir dados através de alterações.

Escreve dados através do método Database::insertBatch. insertBatch adiciona novas linhas a uma tabela. Todas as inserções num único lote são aplicadas de forma atómica.

Este código mostra como escrever os dados através de mutações:

use Google\Cloud\Spanner\SpannerClient;

/**
 * Inserts sample data into the given database.
 *
 * The database and table must already exist and can be created using
 * `create_database`.
 * Example:
 * ```
 * insert_data($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function insert_data(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $operation = $database->transaction(['singleUse' => true])
        ->insertBatch('Singers', [
            ['SingerId' => 1, 'FirstName' => 'Marc', 'LastName' => 'Richards'],
            ['SingerId' => 2, 'FirstName' => 'Catalina', 'LastName' => 'Smith'],
            ['SingerId' => 3, 'FirstName' => 'Alice', 'LastName' => 'Trentor'],
            ['SingerId' => 4, 'FirstName' => 'Lea', 'LastName' => 'Martin'],
            ['SingerId' => 5, 'FirstName' => 'David', 'LastName' => 'Lomond'],
        ])
        ->insertBatch('Albums', [
            ['SingerId' => 1, 'AlbumId' => 1, 'AlbumTitle' => 'Total Junk'],
            ['SingerId' => 1, 'AlbumId' => 2, 'AlbumTitle' => 'Go, Go, Go'],
            ['SingerId' => 2, 'AlbumId' => 1, 'AlbumTitle' => 'Green'],
            ['SingerId' => 2, 'AlbumId' => 2, 'AlbumTitle' => 'Forever Hold Your Peace'],
            ['SingerId' => 2, 'AlbumId' => 3, 'AlbumTitle' => 'Terrified']
        ])
        ->commit();

    print('Inserted data.' . PHP_EOL);
}

Execute o ficheiro de exemplo src/insert_data.php.

php src/insert_data.php test-instance example-db

Deve ver:

Inserted data.

Consultar dados através de SQL

O Spanner suporta uma interface SQL para ler dados, à qual pode aceder na linha de comandos através da Google Cloud CLI ou programaticamente através da biblioteca de cliente do Spanner para PHP.

Na linha de comandos

Execute a seguinte declaração SQL para ler os valores de todas as colunas da tabela Albums:

gcloud spanner databases execute-sql example-db --instance=test-instance \
    --sql='SELECT SingerId, AlbumId, AlbumTitle FROM Albums'

O resultado mostra:

SingerId AlbumId AlbumTitle
1        1       Total Junk
1        2       Go, Go, Go
2        1       Green
2        2       Forever Hold Your Peace
2        3       Terrified

Use a biblioteca cliente do Spanner para PHP

Além de executar uma declaração SQL na linha de comandos, pode emitir a mesma declaração SQL de forma programática através da biblioteca de cliente do Spanner para PHP.

Use Database::execute() para executar a consulta SQL.

Veja como emitir a consulta e aceder aos dados:

use Google\Cloud\Spanner\SpannerClient;

/**
 * Queries sample data from the database using SQL.
 * Example:
 * ```
 * query_data($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function query_data(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $results = $database->execute(
        'SELECT SingerId, AlbumId, AlbumTitle FROM Albums'
    );

    foreach ($results as $row) {
        printf('SingerId: %s, AlbumId: %s, AlbumTitle: %s' . PHP_EOL,
            $row['SingerId'], $row['AlbumId'], $row['AlbumTitle']);
    }
}

Execute o ficheiro de exemplo src/query_data.php.

php src/query_data.php test-instance example-db

Deverá ver o seguinte resultado:

SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace
SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go
SingerId: 2, AlbumId: 1, AlbumTitle: Green
SingerId: 2, AlbumId: 3, AlbumTitle: Terrified
SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk

Os seus resultados não vão estar necessariamente nesta ordem. Se precisar de garantir a ordenação do resultado, use uma cláusula ORDER BY, conforme documentado nas práticas recomendadas de SQL.

Consultar através de um parâmetro SQL

Se a sua aplicação tiver uma consulta executada com frequência, pode melhorar o respetivo desempenho parametrizando-a. A consulta paramétrica resultante pode ser colocada em cache e reutilizada, o que reduz os custos de compilação. Para mais informações, consulte o artigo Use parâmetros de consulta para acelerar as consultas executadas com frequência.

Segue-se um exemplo da utilização de um parâmetro na cláusula WHERE para consultar registos que contêm um valor específico para LastName.

use Google\Cloud\Spanner\SpannerClient;

/**
 * Queries sample data from the database using SQL with a parameter.
 * Example:
 * ```
 * query_data_with_parameter($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function query_data_with_parameter(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $results = $database->execute(
        'SELECT SingerId, FirstName, LastName FROM Singers ' .
        'WHERE LastName = @lastName',
        ['parameters' => ['lastName' => 'Garcia']]
    );

    foreach ($results as $row) {
        printf('SingerId: %s, FirstName: %s, LastName: %s' . PHP_EOL,
            $row['SingerId'], $row['FirstName'], $row['LastName']);
    }
}

Execute o ficheiro de exemplo src/query_data_with_parameter.php.

php src/query_data_with_parameter.php test-instance example-db

Deverá ver o seguinte resultado:

SingerId: 12, FirstName: Melissa, LastName: Garcia

Leia dados através da API de leitura

Além da interface SQL do Spanner, o Spanner também suporta uma interface de leitura.

Use Database::read() para ler linhas da base de dados. Use um objeto KeySet para definir uma coleção de chaves e intervalos de chaves a ler.

Veja como ler os dados:

use Google\Cloud\Spanner\SpannerClient;

/**
 * Reads sample data from the database.
 * Example:
 * ```
 * read_data($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function read_data(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $keySet = $spanner->keySet(['all' => true]);
    $results = $database->read(
        'Albums',
        $keySet,
        ['SingerId', 'AlbumId', 'AlbumTitle']
    );

    foreach ($results->rows() as $row) {
        printf('SingerId: %s, AlbumId: %s, AlbumTitle: %s' . PHP_EOL,
            $row['SingerId'], $row['AlbumId'], $row['AlbumTitle']);
    }
}

Execute a amostra no ficheiro read_data.php.

php read_data.php test-instance example-db

Deverá ver uma saída semelhante à seguinte:

SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk
SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go
SingerId: 2, AlbumId: 1, AlbumTitle: Green
SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold your Peace
SingerId: 2, AlbumId: 3, AlbumTitle: Terrified

Atualize o esquema da base de dados

Suponha que precisa de adicionar uma nova coluna denominada MarketingBudget à tabela Albums. A adição de uma nova coluna a uma tabela existente requer uma atualização ao esquema da base de dados. O Spanner suporta atualizações de esquemas a uma base de dados enquanto a base de dados continua a servir tráfego. As atualizações do esquema não requerem que a base de dados fique offline e não bloqueiam tabelas nem colunas inteiras. Pode continuar a escrever dados na base de dados durante a atualização do esquema. Leia mais acerca das atualizações de esquemas suportadas e do desempenho das alterações de esquemas em Faça atualizações de esquemas.

Adicione uma coluna

Pode adicionar uma coluna na linha de comandos através da Google Cloud CLI ou programaticamente através da biblioteca de cliente do Spanner para PHP.

Na linha de comandos

Use o seguinte comando ALTER TABLE para adicionar a nova coluna à tabela:

GoogleSQL

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='ALTER TABLE Albums ADD COLUMN MarketingBudget INT64'

PostgreSQL

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='ALTER TABLE Albums ADD COLUMN MarketingBudget BIGINT'

Deve ver:

Schema updating...done.

Use a biblioteca cliente do Spanner para PHP

Use Database::updateDdl para modificar o esquema:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\UpdateDatabaseDdlRequest;

/**
 * Adds a new column to the Albums table in the example database.
 * Example:
 * ```
 * add_column($projectId, $instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function add_column(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $databaseName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);

    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => ['ALTER TABLE Albums ADD COLUMN MarketingBudget INT64']
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    printf('Added the MarketingBudget column.' . PHP_EOL);
}

Execute o ficheiro de exemplo src/add_column.php.

php src/add_column.php test-instance example-db

Deve ver:

Added the MarketingBudget column.

Escreva dados na nova coluna

O código seguinte escreve dados na nova coluna. Define MarketingBudget como 100000 para a linha identificada por Albums(1, 1) e como 500000 para a linha identificada por Albums(2, 2).

use Google\Cloud\Spanner\SpannerClient;

/**
 * Updates sample data in the database.
 *
 * This updates the `MarketingBudget` column which must be created before
 * running this sample. You can add the column by running the `add_column`
 * sample or by running this DDL statement against your database:
 *
 *     ALTER TABLE Albums ADD COLUMN MarketingBudget INT64
 *
 * Example:
 * ```
 * update_data($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function update_data(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $operation = $database->transaction(['singleUse' => true])
        ->updateBatch('Albums', [
            ['SingerId' => 1, 'AlbumId' => 1, 'MarketingBudget' => 100000],
            ['SingerId' => 2, 'AlbumId' => 2, 'MarketingBudget' => 500000],
        ])
        ->commit();

    print('Updated data.' . PHP_EOL);
}

Execute o ficheiro de exemplo src/update_data.php.

php src/update_data.php test-instance example-db

Deve ver:

Updated data.

Também pode executar uma consulta SQL ou uma chamada de leitura para obter os valores que acabou de escrever.

Aqui está o código para executar a consulta:

use Google\Cloud\Spanner\SpannerClient;

/**
 * Queries sample data from the database using SQL.
 * This sample uses the `MarketingBudget` column. You can add the column
 * by running the `add_column` sample or by running this DDL statement against
 * your database:
 *
 *      ALTER TABLE Albums ADD COLUMN MarketingBudget INT64
 *
 * Example:
 * ```
 * query_data_with_new_column($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function query_data_with_new_column(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $results = $database->execute(
        'SELECT SingerId, AlbumId, MarketingBudget FROM Albums'
    );

    foreach ($results as $row) {
        printf('SingerId: %s, AlbumId: %s, MarketingBudget: %d' . PHP_EOL,
            $row['SingerId'], $row['AlbumId'], $row['MarketingBudget']);
    }
}

Para executar esta consulta, execute o ficheiro de exemplo src/query-data-with-new-column.php.

php src/query_data_with_new_column.php test-instance example-db

Deve ver:

SingerId: 1, AlbumId: 1, MarketingBudget: 100000
SingerId: 1, AlbumId: 2, MarketingBudget: 0
SingerId: 2, AlbumId: 1, MarketingBudget: 0
SingerId: 2, AlbumId: 2, MarketingBudget: 500000
SingerId: 2, AlbumId: 3, MarketingBudget: 0

Atualize os dados

Pode atualizar dados através de DML numa transação de leitura/escrita.

Usa o método executeUpdate() para executar uma declaração DML.

use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Transaction;

/**
 * Performs a read-write transaction to update two sample records in the
 * database.
 *
 * This will transfer 200,000 from the `MarketingBudget` field for the second
 * Album to the first Album. If the `MarketingBudget` for the second Album is
 * too low, it will raise an exception.
 *
 * Before running this sample, you will need to run the `update_data` sample
 * to populate the fields.
 * Example:
 * ```
 * write_data_with_dml_transaction($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function write_data_with_dml_transaction(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $database->runTransaction(function (Transaction $t) {
        // Transfer marketing budget from one album to another. We do it in a transaction to
        // ensure that the transfer is atomic.
        $transferAmount = 200000;

        $results = $t->execute(
            'SELECT MarketingBudget from Albums WHERE SingerId = 2 and AlbumId = 2'
        );
        $resultsRow = $results->rows()->current();
        $album2budget = $resultsRow['MarketingBudget'];

        // Transaction will only be committed if this condition still holds at the time of
        // commit. Otherwise it will be aborted and the callable will be rerun by the
        // client library.
        if ($album2budget >= $transferAmount) {
            $results = $t->execute(
                'SELECT MarketingBudget from Albums WHERE SingerId = 1 and AlbumId = 1'
            );
            $resultsRow = $results->rows()->current();
            $album1budget = $resultsRow['MarketingBudget'];

            $album2budget -= $transferAmount;
            $album1budget += $transferAmount;

            // Update the albums
            $t->executeUpdate(
                'UPDATE Albums '
                . 'SET MarketingBudget = @AlbumBudget '
                . 'WHERE SingerId = 1 and AlbumId = 1',
                [
                    'parameters' => [
                        'AlbumBudget' => $album1budget
                    ]
                ]
            );
            $t->executeUpdate(
                'UPDATE Albums '
                . 'SET MarketingBudget = @AlbumBudget '
                . 'WHERE SingerId = 2 and AlbumId = 2',
                [
                    'parameters' => [
                        'AlbumBudget' => $album2budget
                    ]
                ]
            );

            $t->commit();

            print('Transaction complete.' . PHP_EOL);
        }
    });
}

Execute o ficheiro de exemplo src/write_data_with_dml_transaction.php.

php src/write_data_with_dml_transaction.php test-instance example-db

Deve ver:

Transaction complete.

Use um índice secundário

Suponhamos que quer obter todas as linhas de Albums que têm valores AlbumTitle num determinado intervalo. Pode ler todos os valores da coluna AlbumTitle através de uma declaração SQL ou de uma chamada de leitura e, em seguida, rejeitar as linhas que não cumprem os critérios, mas esta análise completa da tabela é dispendiosa, especialmente para tabelas com muitas linhas. Em alternativa, pode acelerar a obtenção de linhas quando pesquisa por colunas de chaves não primárias criando um índice secundário na tabela.

A adição de um índice secundário a uma tabela existente requer uma atualização do esquema. Tal como outras atualizações de esquemas, o Spanner suporta a adição de um índice enquanto a base de dados continua a publicar tráfego. O Spanner repreenche automaticamente o índice com os seus dados existentes. Os preenchimentos podem demorar alguns minutos a serem concluídos, mas não tem de colocar a base de dados offline nem evitar escrever na tabela indexada durante este processo. Para mais detalhes, consulte o artigo Adicione um índice secundário.

Depois de adicionar um índice secundário, o Spanner usa-o automaticamente para consultas SQL que provavelmente são executadas mais rapidamente com o índice. Se usar a interface read, tem de especificar o índice que quer usar.

Adicione um índice secundário

Pode adicionar um índice na linha de comandos através da CLI gcloud ou programaticamente através da biblioteca de cliente do Spanner para PHP.

Na linha de comandos

Use o seguinte comando CREATE INDEX para adicionar um índice à base de dados:

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)'

Deve ver:

Schema updating...done.

Usar a biblioteca cliente do Spanner para PHP

Use Database::updateDdl para adicionar um índice:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\UpdateDatabaseDdlRequest;

/**
 * Adds a simple index to the example database.
 * Example:
 * ```
 * create_index($projectId, $instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function create_index(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $databaseName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);
    $statement = 'CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)';
    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => [$statement]
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    printf('Added the AlbumsByAlbumTitle index.' . PHP_EOL);
}

Execute o ficheiro de exemplo src/create_index.php.

php src/create_index.php test-instance example-db

A adição de um índice pode demorar alguns minutos. Depois de adicionar o índice, deve ver o seguinte:

Added the AlbumsByAlbumTitle index.

Leia através do índice

Para consultas SQL, o Spanner usa automaticamente um índice adequado. Na interface de leitura, tem de especificar o índice no seu pedido.

Para usar o índice na interface de leitura, use o método Database::read.

use Google\Cloud\Spanner\SpannerClient;

/**
 * Reads sample data from the database using an index.
 *
 * The index must exist before running this sample. You can add the index
 * by running the `add_index` sample or by running this DDL statement against
 * your database:
 *
 *     CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)
 *
 * Example:
 * ```
 * read_data_with_index($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function read_data_with_index(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $keySet = $spanner->keySet(['all' => true]);
    $results = $database->read(
        'Albums',
        $keySet,
        ['AlbumId', 'AlbumTitle'],
        ['index' => 'AlbumsByAlbumTitle']
    );

    foreach ($results->rows() as $row) {
        printf('AlbumId: %s, AlbumTitle: %s' . PHP_EOL,
            $row['AlbumId'], $row['AlbumTitle']);
    }
}

Execute o ficheiro de exemplo src/read_data_with_index.php.

php src/read_data_with_index.php test-instance example-db

Deve ver:

AlbumId: 2, AlbumTitle: Forever Hold your Peace
AlbumId: 2, AlbumTitle: Go, Go, Go
AlbumId: 1, AlbumTitle: Green
AlbumId: 3, AlbumTitle: Terrified
AlbumId: 1, AlbumTitle: Total Junk

Adicione um índice para leituras apenas de índice

Pode ter reparado que o exemplo de leitura anterior não inclui a leitura da coluna MarketingBudget. Isto deve-se ao facto de a interface de leitura do Spanner não suportar a capacidade de associar um índice a uma tabela de dados para procurar valores que não estão armazenados no índice.

Crie uma definição alternativa de AlbumsByAlbumTitle que armazene uma cópia de MarketingBudget no índice.

Na linha de comandos

GoogleSQL

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget)

PostgreSQL

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) INCLUDE (MarketingBudget)

A adição de um índice pode demorar alguns minutos. Depois de adicionar o índice, deve ver o seguinte:

Schema updating...done.

Usar a biblioteca cliente do Spanner para PHP

Use Database::updateDdl para adicionar um índice com uma cláusula STORING:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\UpdateDatabaseDdlRequest;

/**
 * Adds an storing index to the example database.
 *
 * This sample uses the `MarketingBudget` column. You can add the column
 * by running the `add_column` sample or by running this DDL statement against
 * your database:
 *
 *     ALTER TABLE Albums ADD COLUMN MarketingBudget INT64
 *
 * Example:
 * ```
 * create_storing_index($projectId, $instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function create_storing_index(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $databaseName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);
    $statement = 'CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) ' .
        'STORING (MarketingBudget)';
    $request = new UpdateDatabaseDdlRequest([
        'database' => $databaseName,
        'statements' => [$statement]
    ]);

    $operation = $databaseAdminClient->updateDatabaseDdl($request);

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    printf('Added the AlbumsByAlbumTitle2 index.' . PHP_EOL);
}

Execute o ficheiro de exemplo src/create_storing_index.php.

php src/create_storing_index.php test-instance example-db

Deve ver:

Added the AlbumsByAlbumTitle2 index.

Agora, pode executar uma leitura que obtenha todas as colunas AlbumId, AlbumTitle e MarketingBudget do índice AlbumsByAlbumTitle2:

use Google\Cloud\Spanner\SpannerClient;

/**
 * Reads sample data from the database using an index with a storing
 * clause.
 *
 * The index must exist before running this sample. You can add the index
 * by running the `add_storing_index` sample or by running this DDL statement
 * against your database:
 *
 *     CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle)
 *     STORING (MarketingBudget)
 *
 * Example:
 * ```
 * read_data_with_storing_index($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function read_data_with_storing_index(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $keySet = $spanner->keySet(['all' => true]);
    $results = $database->read(
        'Albums',
        $keySet,
        ['AlbumId', 'AlbumTitle', 'MarketingBudget'],
        ['index' => 'AlbumsByAlbumTitle2']
    );

    foreach ($results->rows() as $row) {
        printf('AlbumId: %s, AlbumTitle: %s, MarketingBudget: %d' . PHP_EOL,
            $row['AlbumId'], $row['AlbumTitle'], $row['MarketingBudget']);
    }
}

Execute o ficheiro de exemplo src/read_data_with_storing_index.php.

php src/read_data_with_storing_index.php test-instance example-db

Deverá ver uma saída semelhante à seguinte:

AlbumId: 2, AlbumTitle: Forever Hold your Peace, MarketingBudget: 300000
AlbumId: 2, AlbumTitle: Go, Go, Go, MarketingBudget: 0
AlbumId: 1, AlbumTitle: Green, MarketingBudget: 0
AlbumId: 3, AlbumTitle: Terrified, MarketingBudget: 0
AlbumId: 1, AlbumTitle: Total Junk, MarketingBudget: 300000

Obtenha dados através de transações só de leitura

Suponhamos que quer executar mais do que uma leitura na mesma data/hora. As transações de leitura exclusiva observam um prefixo consistente do histórico de confirmações de transações, pelo que a sua aplicação recebe sempre dados consistentes. Use um objeto Snapshot para executar transações de leitura. Use o método Database::snapshot para obter um objeto Snapshot.

O exemplo seguinte mostra como executar uma consulta e fazer uma leitura na mesma transação só de leitura:

use Google\Cloud\Spanner\SpannerClient;

/**
 * Reads data inside of a read-only transaction.
 *
 * Within the read-only transaction, or "snapshot", the application sees
 * consistent view of the database at a particular timestamp.
 * Example:
 * ```
 * read_only_transaction($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function read_only_transaction(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $snapshot = $database->snapshot();
    $results = $snapshot->execute(
        'SELECT SingerId, AlbumId, AlbumTitle FROM Albums'
    );
    print('Results from the first read:' . PHP_EOL);
    foreach ($results as $row) {
        printf('SingerId: %s, AlbumId: %s, AlbumTitle: %s' . PHP_EOL,
            $row['SingerId'], $row['AlbumId'], $row['AlbumTitle']);
    }

    // Perform another read using the `read` method. Even if the data
    // is updated in-between the reads, the snapshot ensures that both
    // return the same data.
    $keySet = $spanner->keySet(['all' => true]);
    $results = $database->read(
        'Albums',
        $keySet,
        ['SingerId', 'AlbumId', 'AlbumTitle']
    );

    print('Results from the second read:' . PHP_EOL);
    foreach ($results->rows() as $row) {
        printf('SingerId: %s, AlbumId: %s, AlbumTitle: %s' . PHP_EOL,
            $row['SingerId'], $row['AlbumId'], $row['AlbumTitle']);
    }
}

Execute o ficheiro de exemplo src/read_only_transaction.php.

php src/read_only_transaction.php test-instance example-db

Deverá ver uma saída semelhante à seguinte:

Results from first read:
SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace
SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go
SingerId: 2, AlbumId: 1, AlbumTitle: Green
SingerId: 2, AlbumId: 3, AlbumTitle: Terrified
SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk
Results from second read:
SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk
SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go
SingerId: 2, AlbumId: 1, AlbumTitle: Green
SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace
SingerId: 2, AlbumId: 3, AlbumTitle: Terrified

Limpeza

Para evitar incorrer em cobranças adicionais na sua conta do Cloud Billing pelos recursos usados neste tutorial, elimine a base de dados e a instância que criou.

Elimine a base de dados

Se eliminar uma instância, todas as bases de dados na mesma são eliminadas automaticamente. Este passo mostra como eliminar uma base de dados sem eliminar uma instância (continua a incorrer em custos pela instância).

Na linha de comandos

gcloud spanner databases delete example-db --instance=test-instance

Usar a Google Cloud consola

  1. Aceda à página Instâncias do Spanner na Google Cloud consola.

    Aceda à página Instâncias

  2. Clique na instância.

  3. Clique na base de dados que quer eliminar.

  4. Na página Detalhes da base de dados, clique em Eliminar.

  5. Confirme que quer eliminar a base de dados e clique em Eliminar.

Elimine a instância

A eliminação de uma instância elimina automaticamente todas as bases de dados criadas nessa instância.

Na linha de comandos

gcloud spanner instances delete test-instance

Usar a Google Cloud consola

  1. Aceda à página Instâncias do Spanner na Google Cloud consola.

    Aceda à página Instâncias

  2. Clique na instância.

  3. Clique em Eliminar.

  4. Confirme que quer eliminar a instância e clique em Eliminar.

O que se segue?