Como usar o driver JDBC de código aberto

Aqui, mostramos como executar operações básicas no Cloud Spanner usando o driver JDBC de código aberto.

Instalar o driver JDBC

Siga as etapas em Bibliotecas de cliente do Cloud Spanner para configurar a autenticação e, em seguida, adicione a dependência com.google.cloud.google-cloud-spanner-jdbc (em inglês) ao arquivo de configuração da compilação do seu aplicativo. Por exemplo, se você usar o Maven, defina o groupId da dependência como com.google.cloud e o artifactId como google-cloud-spanner-jdbc.

Executar uma atualização de esquema

No exemplo de código a seguir, adicionamos a tabela Musicians ao banco de dados.

Primeiro, crie uma conexão JDBC:

static String getJdbcConnectionUrl(String projectId, String instance,
    String database) {
  String jdbcUrlFormat =
      "jdbc:cloudspanner:/projects/%s/instances/%s/databases/%s;credentials=%s";
  String credentialsUrl = "path/to/service-account/credentials/file.json";
  // ...
  String url = String.format(
      jdbcUrlFormat, projectId, instance, database, credentialsUrl);
  return url;
}

Em seguida, crie a tabela Musicians:

static void createTableWithJdbc(String projectId, String instance,
    String database) throws SQLException {
  String jdbcUrl = getJdbcConnectionUrl(projectId, instance, database);
  try (Connection connection = DriverManager.getConnection(jdbcUrl)) {
    // Create a test table in a DDL BATCH.
    connection.setAutoCommit(false);
    java.sql.Statement statement = connection.createStatement();
    statement.execute("START BATCH DDL");
    statement.execute(
        "CREATE TABLE Musicians ("
            + "  MusicianId  INT64 NOT NULL,"
            + "  FirstName  STRING(1024),"
            + "  LastName   STRING(1024),"
            + "  MusicianInfo BYTES(MAX)"
            + ") PRIMARY KEY (MusicianId)");
    statement.execute("RUN BATCH");
    connection.commit();
  } catch (SQLException e) {
    if (e.getErrorCode() == Code.ABORTED.value()) {
      // Transaction aborted, retry.
    } else {
      throw e;
    }
  }
  System.out.println("Created table [Musicians].\n");
}

Use uma transação no modo de confirmação automática para adicionar e excluir linhas

Se você não precisa realizar várias operações como um grupo, use uma transação no modo de confirmação automática. O modo de confirmação automática exige menos código do que uma transação em lote. O exemplo de código a seguir usa uma transação no modo de confirmação automática para adicionar e excluir linhas da tabela Singers:

static void insertAndDeleteWithJdbc(String projectId, String instance,
    String database) throws SQLException {
  long rowCountInserted = 0;
  long rowCountDeleted = 0;
  String jdbcUrl = getJdbcConnectionUrl(projectId, instance, database);
  try (Connection connection = DriverManager.getConnection(jdbcUrl)) {
    while (true) {
      try {
        try (PreparedStatement ps = connection.prepareStatement(
          "INSERT INTO Singers (SingerId, FirstName, LastName) "
            + "VALUES (?, ?, ?)")) {
          ps.setLong(1, 16);
          ps.setString(2, "Test");
          ps.setString(3, "Singer 16");
          rowCountInserted = ps.executeUpdate();
        }
        try (PreparedStatement ps = connection.prepareStatement(
          "DELETE FROM Singers WHERE Lastname = ?")) {
          ps.setString(1, "Lomond");
          rowCountDeleted = ps.executeUpdate();
        }
        break;
      } catch (SQLException e) {
        if (e.getErrorCode() == Code.ABORTED.value()) {
          // Transaction aborted, retry.
        } else {
          throw e;
        }
      }
    }
  }
  System.out.printf("%d record inserted.\n", rowCountInserted);
  System.out.printf("%d record deleted.\n", rowCountDeleted);
}

Usar uma transação em lote para adicionar e excluir linhas

Para controlar se o Cloud Spanner confirma várias operações juntas como um grupo, use uma transação em lote. No exemplo de código a seguir, usamos connection.setAutoCommit(false) e connection.commit() para adicionar e excluir linhas da tabela Singers.

static void batchTransactionWithJdbc(String projectId, String instance,
    String database) throws SQLException {
  long rowCountInserted = 0;
  long rowCountDeleted = 0;
  String jdbcUrl = getJdbcConnectionUrl(projectId, instance, database);
  try (Connection connection = DriverManager.getConnection(jdbcUrl)) {
    while (true) {
      try {
        connection.setAutoCommit(false);
        try (PreparedStatement ps = connection.prepareStatement(
          "INSERT INTO Singers (SingerId, FirstName, LastName) "
          + "VALUES (?, ?, ?)")) {
          ps.setLong(1, 17);
          ps.setString(2, "Test");
          ps.setString(3, "Singer 17");
          rowCountInserted = ps.executeUpdate();
        }
        try (PreparedStatement ps = connection.prepareStatement(
          "DELETE FROM Singers WHERE Lastname = ?")) {
          ps.setString(1, "Martin");
          rowCountDeleted = ps.executeUpdate();
        }
        connection.commit();
        break;
      } catch (SQLException e) {
        if (e.getErrorCode() == Code.ABORTED.value()) {
          // Transaction aborted, retry.
        } else {
          throw e;
        }
      }
    }
  }
  System.out.printf("%d record inserted.\n", rowCountInserted);
  System.out.printf("%d record deleted.\n", rowCountDeleted);
}

Executar uma consulta SQL

Use a seguinte consulta para retornar todas as linhas na tabela Albums com títulos que começam com a letra G:

static void queryWithJdbc(String projectId, String instance,
    String database) throws SQLException {
  String jdbcUrl = getJdbcConnectionUrl(projectId, instance, database);
  try (Connection connection = DriverManager.getConnection(jdbcUrl)) {
    PreparedStatement ps = connection.prepareStatement(
        "SELECT * FROM Albums WHERE AlbumTitle LIKE ?");
    ps.setQueryTimeout(10);
    ps.setString(1, "G%");
    try (java.sql.ResultSet rs = ps.executeQuery()) {
      while (rs.next()) {
        System.out
            .println(String.format("%d %s", rs.getLong("AlbumId"),
                rs.getString("AlbumTitle")));
      }
    }
  } catch (SQLException e) {
    if (e.getErrorCode() == Code.ABORTED.value()) {
      // Transaction aborted, retry.
    } else {
      throw e;
    }
  }
}

Instruções de gerenciamento de sessão

Além das instruções de consulta SQL, o driver JDBC (Java Database Connectivity) de código aberto do Cloud Spanner é compatível com as instruções de gerenciamento de sessão, que permitem modificar o estado da conexão, executar transações e executar lotes de instruções com eficiência.

Instruções de conexão

As instruções a seguir alteram ou exibem as propriedades da conexão atual.

SHOW VARIABLE READONLY

Retorna um conjunto de resultados com uma linha e uma coluna do tipo BOOL, indicando se a conexão está ou não em modo somente leitura.

SET READONLY

Sintaxe
SET READONLY = { true | false }

Define se a conexão está no modo somente leitura.

Execute esta instrução apenas enquanto não houver uma transação ativa.

SHOW VARIABLE AUTOCOMMIT

Retorna um conjunto de resultados com uma linha e uma coluna do tipo BOOL, indicando se a conexão está no modo AUTOCOMMIT.

SET AUTOCOMMIT

Sintaxe
SET AUTOCOMMIT = { true | false }

Define o modo AUTOCOMMIT da conexão.

Execute esta instrução apenas enquanto não houver uma transação ativa.

SHOW VARIABLE RETRY_ABORTS_INTERNALLY

Retorna um conjunto de resultados com uma linha e uma coluna do tipo BOOL, indicando se a conexão tenta repetir automaticamente as transações canceladas.

SET RETRY_ABORTS_INTERNALLY

Sintaxe
SET RETRY_ABORTS_INTERNALLY = { true | false }

Define se a conexão tenta repetir automaticamente as transações canceladas.

Execute esta instrução apenas enquanto não houver uma transação ativa.

Ao ativar RETRY_ABORTS_INTERNALLY, a conexão mantém uma soma de verificação criptográfica de todos os dados que a conexão retorna ao aplicativo cliente e todas as contagens de atualização relatadas pela conexão durante a transação. Se o Cloud Spanner cancelar a transação, a conexão tentará executar a mesma transação e verificará se os dados retornados são exatamente iguais aos dados retornados na transação original. Se os dados forem correspondentes, o Cloud Spanner continuará a transação. Caso contrário, a transação falhará, lançando AbortedDueToConcurrentModification.

Essa configuração é ativada por padrão. Recomendamos desativar essa configuração se o aplicativo já tentou novamente as transações canceladas.

SHOW VARIABLE AUTOCOMMIT_DML_MODE

Retorna um conjunto de resultados com uma linha e uma coluna do tipo STRING indicando o modo de confirmação automática para as instruções da linguagem de manipulação de dados (DML, na sigla em inglês).

Essa variável só tem efeito quando você ativa o modo AUTOCOMMIT na conexão.

SET AUTOCOMMIT_DML_MODE

Sintaxe
SET AUTOCOMMIT_DML_MODE = { 'TRANSACTIONAL' | 'PARTITIONED_NON_ATOMIC' }

Define o modo de confirmação automática para instruções DML:

  • No modo TRANSACTIONAL, o driver executa instruções DML como transações atômicas separadas. O driver cria uma nova transação, executa a instrução DML e realiza a confirmação da transação após a execução bem-sucedida ou reverte a transação no caso de um erro.
  • No modo PARTITIONED_NON_ATOMIC, o driver executa instruções DML como instruções de atualização particionadas. Uma instrução de atualização particionada pode ser executada como uma série de muitas transações, cada uma abrangendo um subconjunto das linhas afetadas, e a instrução particionada fornece semântica enfraquecida em troca de melhor escalonabilidade e desempenho.

Execute essa instrução somente se tiver ativado o modo AUTOCOMMIT.

SHOW VARIABLE STATEMENT_TIMEOUT

Retorna um conjunto de resultados com uma linha e uma coluna do tipo STRING, indicando o valor do tempo limite atual para instruções. O valor é um número inteiro seguido por um sufixo que indica a unidade de tempo. Um valor de NULL indica que não há um valor de tempo limite definido. As instruções que demoram mais do que o tempo limite especificado, caso ele tenha sido definido, causarão java.sql.SQLTimeoutException e invalidarão a transação.

SET STATEMENT_TIMEOUT

Sintaxe
SET STATEMENT_TIMEOUT = { '<INT64>{ s | ms | us | ns }' | NULL }

Define o valor de tempo limite da instrução para todas as instruções subsequentes na conexão. Definir o valor de tempo limite como NULL desativa os tempos limites da instrução para a conexão.

Os blocos de tempo compatíveis são estes:

  • s: segundos
  • ms: milésimos de segundo
  • us: microssegundos
  • ns: nanossegundos

O tempo limite de uma instrução durante uma transação invalida a transação, todas as instruções subsequentes na transação invalidada falham (exceto ROLLBACK) e o driver JDBC gera um java.sql.SQLTimeoutException.

SHOW VARIABLE READ_ONLY_STALENESS

Retorna um conjunto de resultados com uma linha e uma coluna do tipo STRING que indica o valor atual da configuração de inatividade somente leitura que o Cloud Spanner usa para transações e consultas somente leitura no modo AUTOCOMMIT. A configuração padrão é STRONG.

SET READ_ONLY_STALENESS

Sintaxe
SET READ_ONLY_STALENESS = { 'STRONG' | 'MIN_READ_TIMESTAMP <timestamp>' | 'READ_TIMESTAMP <timestamp>' |
    'MAX_STALENESS <INT64>{ s | ms | us | ns }' | 'EXACT_STALENESS <INT64>{ s | ms | us | ns }' }

Define a configuração de inatividade somente leitura para todas as transações somente leitura subsequentes, enquanto não estiverem no modo AUTOCOMMIT, e para todas as consultas no modo AUTOCOMMIT.

As opções de limite de carimbo de data/hora são as seguintes:

Os carimbo de data/hora precisam usar o seguinte formato:

YYYY-[M]M-[D]DT[[H]H:[M]M:[S]S[.DDDDDD]][timezone]

As unidades de tempo compatíveis para definir os valores MAX_STALENESS e EXACT_STALENESS são estes:

  • s: segundos
  • ms: milésimos de segundo
  • us: microssegundos
  • ns: nanossegundos

Execute esta instrução apenas enquanto não houver uma transação ativa.

Instruções da transação

As seguintes instruções gerenciam e confirmam as transações do Cloud Spanner.

SHOW VARIABLE READ_TIMESTAMP

Retorna um conjunto de resultados com uma linha e uma coluna do tipo TIMESTAMP que contém a leitura do carimbo de data/hora da transação somente leitura mais recente. Essa instrução retorna um carimbo de data/hora apenas quando uma transação somente leitura ainda está ativa e executou pelo menos uma consulta ou imediatamente após uma transação somente leitura ser confirmada e antes de uma nova transação. Caso contrário, o resultado será NULL.

SHOW VARIABLE COMMIT_TIMESTAMP

Retorna um conjunto de resultados com uma linha e uma coluna do tipo TIMESTAMP que contém o carimbo de data/hora de consolidação da última transação de leitura e gravação confirmada pelo Cloud Spanner. Essa instrução retorna um carimbo de data/hora apenas quando você o executa, depois de confirmar uma transação de leitura e gravação e antes de executar qualquer SELECT, DML ou instruções de alteração de esquema subsequentes. Caso contrário, o resultado será NULL.

BEGIN [TRANSACTION]

Inicia uma nova transação.

  • Se você ativou o modo AUTOCOMMIT, esta instrução temporariamente remove a conexão do modo AUTOCOMMIT. A conexão retorna ao modo AUTOCOMMIT quando a transação termina.
  • Caso você tenha desativado o modo AUTOCOMMIT, esta instrução é opcional e não tem efeito.

Execute esta instrução apenas enquanto não houver uma transação ativa.

COMMIT [TRANSACTION]

Confirma a transação atual.

  • A confirmação de uma transação de leitura e gravação torna todas as atualizações desta transação visíveis para outras transações e libera todos os bloqueios da transação no Cloud Spanner.
  • A confirmação de uma transação somente leitura encerra a transação somente leitura atual. Qualquer instrução subsequente inicia uma nova transação. Não há diferença semântica entre COMMIT e ROLLBACK para uma transação somente leitura.

É possível executar essa instrução somente quando houver uma transação ativa.

ROLLBACK [TRANSACTION]

Executa um ROLLBACK da transação atual.

  • Realizar um ROLLBACK de uma transação de leitura e gravação limpa todas as mutações armazenadas em buffer, reverte a transação no Cloud Spanner e libera todos os bloqueios retidos pela transação.
  • Realizar um ROLLBACK de uma transação somente leitura encerra a transação somente leitura atual. Qualquer instrução subsequente inicia uma nova transação. Não há diferença semântica entre COMMIT e ROLLBACK para uma transação somente leitura em uma conexão.

É possível executar essa instrução somente quando houver uma transação ativa.

SET TRANSACTION

Sintaxe
SET TRANSACTION { READ ONLY | READ WRITE }

Define o modo de transação da transação atual.

Execute essa instrução somente quando você não ativar o modo AUTOCOMMIT ou se tiver iniciado uma transação temporária executando BEGIN [TRANSACTION] e ainda não tiver executado nenhuma instrução na transação.

Instruções em lote

As instruções a seguir gerenciam lotes de instruções DDL e os enviam para o Cloud Spanner.

START BATCH DDL

Inicia um lote de instruções DDL na conexão. Todas as instruções subsequentes durante o lote precisam ser instruções DDL. As instruções DDL são armazenadas em buffer localmente e enviadas ao Cloud Spanner como um lote quando você executa RUN BATCH. Executar várias instruções DDL como um lote é, geralmente, mais rápido do que executá-las separadamente.

Execute esta instrução apenas enquanto não houver uma transação ativa.

RUN BATCH

Envia todas as instruções DDL armazenadas em buffer no lote DDL atual para o banco de dados, aguarda o Cloud Spanner executar essas instruções e encerra o lote DDL atual.

Se o Cloud Spanner não puder executar pelo menos uma instrução DDL, RUN BATCH retornará um erro para a primeira instrução DDL que o Cloud Spanner não puder executar. Caso contrário, RUN BATCH retorna com sucesso.

ABORT BATCH

Limpa todas as instruções DDL armazenadas em buffer no lote DDL e encerra o lote.

Execute essa instrução somente quando um lote DDL estiver ativo. É possível usar ABORT BATCH independentemente do lote ter ou não instruções DDL armazenadas em buffer.

A seguir

Veja as respostas para perguntas frequentes sobre o driver JDBC de código aberto.