Início Rápido: Usar Java e JDBC para Azure HorizonDB (versão prévia)

Este artigo demonstra como criar um aplicativo de exemplo que usa Java e JDBC para armazenar e recuperar informações em Azure HorizonDB (versão prévia).

O JDBC é a API de Java padrão para se conectar a bancos de dados relacionais tradicionais.

As etapas neste artigo incluem a autenticação postgreSQL.

A autenticação PostgreSQL usa contas armazenadas no PostgreSQL e você precisa gerenciar a rotação das senhas por conta própria.

Pré-requisitos

Preparar o ambiente de trabalho

Primeiro, use o comando a seguir para configurar algumas variáveis de ambiente.

export AZ_RESOURCE_GROUP=database-workshop
export AZ_DATABASE_CLUSTER_NAME=<YOUR_DATABASE_CLUSTER_NAME>
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_POSTGRESQL_ADMIN_USERNAME=demo
export AZ_POSTGRESQL_ADMIN_PASSWORD=<YOUR_POSTGRESQL_ADMIN_PASSWORD>
export AZ_POSTGRESQL_NON_ADMIN_USERNAME=demo-non-admin
export AZ_POSTGRESQL_NON_ADMIN_PASSWORD=<YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>
export AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>

Substitua os marcadores de posição pelos seguintes valores, que são usados ao longo deste artigo:

  • <YOUR_DATABASE_CLUSTER_NAME>: o nome do cluster do Azure HorizonDB, que deve ser único em toda a Assinatura do Azure e o grupo de recursos.
  • <YOUR_DATABASE_NAME>: o nome do banco de dados que você está usando em seu cluster Azure HorizonDB.
  • <YOUR_AZURE_REGION>: a região do Azure a ser usada. Você pode usar australiaeast por padrão, mas configurar uma região mais próxima de onde você mora. Você pode ver a lista completa de regiões disponíveis inserindo az account list-locations.
  • <YOUR_POSTGRESQL_ADMIN_PASSWORD> e <YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>: A senha do cluster do Azure HorizonDB. Essa senha deveria ter um mínimo de oito caracteres. A senha deve conter caracteres de três das seguintes categorias: letras maiúsculas, letras minúsculas, números (0-9) e caracteres não alfanuméricos (!, $, #, % e assim por diante).
  • <YOUR_LOCAL_IP_ADDRESS>: o endereço IP do computador local, do qual você executa seu aplicativo Spring Boot. Uma maneira conveniente de descobrir é abrir whatismyip.akamai.com.

Em seguida, crie um grupo de recursos usando o seguinte comando:

az group create \
    --name $AZ_RESOURCE_GROUP \
    --location $AZ_LOCATION \
    --output tsv

Criar um cluster Azure HorizonDB

Note

Não inclua nenhuma informação pessoal, sensível ou confidencial em nomes de recursos (por exemplo, nome de tabela, nome de banco de dados) e tags de recursos. Os dados que você insere nesses campos não são considerados dados do cliente.

As seções a seguir descrevem como criar e configurar seu cluster de banco de dados.

Criar um cluster Azure HorizonDB

Configurar usuário administrador

Primeiro, crie uma instância Azure HorizonDB gerenciada.

Note

Para obter informações mais detalhadas sobre como criar Azure HorizonDB, consulte Criar um cluster Azure HorizonDB.

az horizondb create \
  --resource-group $AZ_RESOURCE_GROUP \
  --name $AZ_DATABASE_CLUSTER_NAME \
  --location $AZ_LOCATION \
  --version 17 \
  --administrator-login $AZ_POSTGRESQL_ADMIN_USERNAME \
  --administrator-login-password $AZ_POSTGRESQL_ADMIN_PASSWORD \
  --v-cores 2 \
  --yes \
  --output tsv

Esse comando cria um pequeno cluster Azure HorizonDB.

Está tendo algum problema? Avise-nos.

Configurar uma regra de firewall para sua instância do Azure HorizonDB

As instâncias do HorizonDB do Azure são seguras por padrão. Eles têm um firewall que bloqueia todas as conexões de entrada. Para usar seu banco de dados, adicione uma regra de firewall que conceda acesso ao endereço IP local ao servidor de banco de dados.

Como você configurou seu endereço IP local no início deste artigo, você pode abrir o firewall do servidor executando o seguinte comando:

az horizondb firewall-rule create \
  --resource-group $AZ_RESOURCE_GROUP \
  --cluster-name $AZ_DATABASE_CLUSTER_NAME \
  --firewall-rule-name $AZ_DATABASE_CLUSTER_NAME-database-allow-local-ip \
  --start-ip-address $AZ_LOCAL_IP_ADDRESS \
  --end-ip-address $AZ_LOCAL_IP_ADDRESS \
  --output tsv

Se você estiver se conectando ao cluster Azure HorizonDB de Subsistema do Windows para Linux (WSL) em um computador Windows, precisará adicionar a ID do host WSL ao firewall.

Obtenha o endereço IP do computador host executando o seguinte comando no WSL:

cat /etc/resolv.conf

Copie o endereço IP que segue o termo nameservere use o seguinte comando para definir uma variável de ambiente para o endereço IP WSL:

AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

Em seguida, use o seguinte comando para abrir o firewall do servidor para seu aplicativo baseado em WSL:

az horizondb firewall-rule create \
  --resource-group $AZ_RESOURCE_GROUP \
  --cluster-name $AZ_DATABASE_CLUSTER_NAME \
  --firewall-rule-name $AZ_DATABASE_CLUSTER_NAME-database-allow-local-ip \
  --start-ip-address $AZ_WSL_IP_ADDRESS \
  --end-ip-address $AZ_WSL_IP_ADDRESS \
  --output tsv

Criar um banco de dados Azure HorizonDB

Crie um script SQL chamado create_database.sql para criar um novo banco de dados em seu cluster. Adicione o seguinte conteúdo e salve o arquivo localmente:

cat << EOF > create_database.sql
CREATE DATABASE "$AZ_DATABASE_NAME";
EOF

Execute este comando para obter o nome de domínio totalmente qualificado do Azure HorizonDB e copiar o valor clusterName:

az horizondb show \
  --resource-group $AZ_RESOURCE_GROUP \
  --name $AZ_DATABASE_CLUSTER_NAME \
  --query "{clusterName:properties.fullyQualifiedDomainName, adminUser:properties.administratorLogin}" \
  --output table

Copie o clusterName valor e use-o no seguinte comando:

AZ_HORIZONDB_FQDN=<the-copied-clusterName-value>

Em seguida, execute o seguinte comando para executar o script SQL e criar seu banco de dados:

psql "host=$AZ_HORIZONDB_FQDN user=$AZ_POSTGRESQL_ADMIN_USERNAME dbname=$AZ_DATABASE_NAME port=5432 password=$AZ_POSTGRESQL_ADMIN_PASSWORD sslmode=require" < create_database.sql

Agora, execute o seguinte comando para excluir o arquivo de script SQL temporário:

rm create_database.sql

Criar um usuário não administrador do Azure HorizonDB e conceder permissões

Em seguida, crie um usuário não administrador e conceda todas as permissões ao banco de dados.

Crie um script SQL chamado create_user.sql para criar um usuário não administrador. Adicione o seguinte conteúdo e salve o arquivo localmente:

cat << EOF > create_user.sql
CREATE ROLE "$AZ_POSTGRESQL_NON_ADMIN_USERNAME" WITH LOGIN PASSWORD '$AZ_POSTGRESQL_NON_ADMIN_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE $AZ_DATABASE_NAME TO "$AZ_POSTGRESQL_NON_ADMIN_USERNAME";
EOF

Em seguida, execute o seguinte comando para executar o script SQL e criar o Microsoft Entra usuário não administrador:

psql "host=$AZ_HORIZONDB_FQDN user=$AZ_POSTGRESQL_ADMIN_USERNAME dbname=$AZ_DATABASE_NAME port=5432 password=$AZ_POSTGRESQL_ADMIN_PASSWORD sslmode=require" < create_user.sql

Agora, execute o seguinte comando para excluir o arquivo de script SQL temporário:

rm create_user.sql

Criar um projeto Java

Usando seu IDE favorito, crie um novo projeto de Java usando Java 8 ou posterior. Adicione um arquivo pom.xml no diretório raiz com o seguinte conteúdo:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
      <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.3.6</version>
      </dependency>
    </dependencies>
</project>

Esse arquivo é um Apache Maven que configura seu projeto a ser usado:

  • Java 8
  • Um driver PostgreSQL recente para Java

Preparar um arquivo de configuração para se conectar ao Azure HorizonDB

Crie um arquivo src/main/resources/application.properties e adicione o seguinte conteúdo:

cat << EOF > src/main/resources/application.properties
url=jdbc:postgresql://${AZ_HORIZONDB_FQDN}:5432/${AZ_DATABASE_NAME}?sslmode=require
user=${AZ_POSTGRESQL_NON_ADMIN_USERNAME}
password=${AZ_POSTGRESQL_NON_ADMIN_PASSWORD}
EOF

Note

A propriedade de configuração url inclui ?sslmode=require para garantir que o driver JDBC use TLS (Transport Layer Security) ao se conectar ao banco de dados. Azure HorizonDB requer TLS e é uma prática de segurança recomendada.

Criar um arquivo SQL para gerar o esquema do banco de dados

Use um arquivo src/main/resources/schema.sql para criar um esquema de banco de dados. Crie esse arquivo com o seguinte conteúdo:

DROP TABLE IF EXISTS todo;
CREATE TABLE todo (id SERIAL PRIMARY KEY, description text, details text, done BOOLEAN);

Codificar o aplicativo

Conectar-se ao banco de dados

Em seguida, adicione o código Java que usa o JDBC para armazenar e recuperar dados de sua instância Azure HorizonDB.

Crie um arquivo src/main/java/DemoApplication.java e adicione o seguinte conteúdo:

package com.example.demo;

import java.sql.*;
import java.util.*;
import java.util.logging.Logger;

public class DemoApplication {

    private static final Logger log;

    static {
        System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$-7s] %5$s %n");
        log =Logger.getLogger(DemoApplication.class.getName());
    }

    public static void main(String[] args) throws Exception {
        log.info("Loading application properties");
        Properties properties = new Properties();
        properties.load(DemoApplication.class.getClassLoader().getResourceAsStream("application.properties"));

        log.info("Connecting to the database");
        Connection connection = DriverManager.getConnection(properties.getProperty("url"), properties);
        log.info("Database connection test: " + connection.getCatalog());

        log.info("Create database schema");
        Scanner scanner = new Scanner(DemoApplication.class.getClassLoader().getResourceAsStream("schema.sql"));
        Statement statement = connection.createStatement();
        while (scanner.hasNextLine()) {
            statement.execute(scanner.nextLine());
        }

        /*
        Todo todo = new Todo(1L, "configuration", "congratulations, you have set up JDBC correctly!", true);
        insertData(todo, connection);
        todo = readData(connection);
        todo.setDetails("congratulations, you have updated data!");
        updateData(todo, connection);
        deleteData(todo, connection);
        */

        log.info("Closing database connection");
        connection.close();
    }
}

Está tendo algum problema? Avise-nos.

Esse código Java usa os arquivos application.properties e schema.sql que criamos anteriormente, para se conectar à instância Azure HorizonDB e criar um esquema que armazena nossos dados.

Neste arquivo, você pode ver que comentamos métodos para inserir, ler, atualizar e excluir dados: codificaremos esses métodos no restante deste artigo e você poderá descompactá-los um após o outro.

Note

As credenciais de banco de dados são armazenadas nas propriedades user e password no arquivo application.properties. Essas credenciais são usadas durante a execução de DriverManager.getConnection(properties.getProperty("url"), properties);, pois o arquivo de propriedades é passado como um argumento.

Agora, você pode executar esta classe principal com a sua ferramenta favorita:

  • Usando o IDE, você deve clicar com o botão direito do mouse na classe DemoApplication e executá-la.
  • Usando o Maven, você pode executar o aplicativo por meio do: mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication".

O aplicativo deve se conectar à instância do Azure HorizonDB, criar um esquema de banco de dados e fechar a conexão, como você deve ver nos logs do console:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Closing database connection

Criar uma classe de domínio

Crie uma classe Java Todo, ao lado da classe DemoApplication e adicione o seguinte código:

package com.example.demo;

public class Todo {

    private Long id;
    private String description;
    private String details;
    private boolean done;

    public Todo() {
    }

    public Todo(Long id, String description, String details, boolean done) {
        this.id = id;
        this.description = description;
        this.details = details;
        this.done = done;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }

    @Override
    public String toString() {
        return "Todo{" +
                "id=" + id +
                ", description='" + description + '\'' +
                ", details='" + details + '\'' +
                ", done=" + done +
                '}';
    }
}

Essa classe é um modelo de domínio mapeado na tabela todo que você criou ao executar o script schema.sql.

Inserir dados no Azure HorizonDB

No arquivo src/main/java/DemoApplication.java, após o método principal, adicione o seguinte método para inserir dados no banco de dados:

private static void insertData(Todo todo, Connection connection) throws SQLException {
    log.info("Insert data");
    PreparedStatement insertStatement = connection
            .prepareStatement("INSERT INTO todo (id, description, details, done) VALUES (?, ?, ?, ?);");

    insertStatement.setLong(1, todo.getId());
    insertStatement.setString(2, todo.getDescription());
    insertStatement.setString(3, todo.getDetails());
    insertStatement.setBoolean(4, todo.isDone());
    insertStatement.executeUpdate();
}

Agora você pode descomentar as duas linhas seguintes no método main:

Todo todo = new Todo(1L, "configuration", "congratulations, you have set up JDBC correctly!", true);
insertData(todo, connection);

A execução da classe principal deve produzir a seguinte saída:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Closing database connection

Ler dados do Azure HorizonDB

Vamos ler os dados inseridos anteriormente para validar se o nosso código funciona corretamente.

No arquivo src/main/java/DemoApplication.java, após o método insertData, adicione o seguinte método para ler dados do banco de dados:

private static Todo readData(Connection connection) throws SQLException {
    log.info("Read data");
    PreparedStatement readStatement = connection.prepareStatement("SELECT * FROM todo;");
    ResultSet resultSet = readStatement.executeQuery();
    if (!resultSet.next()) {
        log.info("There is no data in the database!");
        return null;
    }
    Todo todo = new Todo();
    todo.setId(resultSet.getLong("id"));
    todo.setDescription(resultSet.getString("description"));
    todo.setDetails(resultSet.getString("details"));
    todo.setDone(resultSet.getBoolean("done"));
    log.info("Data read from the database: " + todo.toString());
    return todo;
}

Agora você pode descomentar a seguinte linha no método main:

todo = readData(connection);

A execução da classe principal deve produzir a seguinte saída:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have set up JDBC correctly!', done=true}
[INFO   ] Closing database connection

Atualizar dados no Azure HorizonDB

Vamos atualizar os dados que inserimos anteriormente.

Ainda no arquivo src/main/java/DemoApplication.java, após o método readData, adicione o seguinte método para atualizar os dados no banco de dados:

private static void updateData(Todo todo, Connection connection) throws SQLException {
    log.info("Update data");
    PreparedStatement updateStatement = connection
            .prepareStatement("UPDATE todo SET description = ?, details = ?, done = ? WHERE id = ?;");

    updateStatement.setString(1, todo.getDescription());
    updateStatement.setString(2, todo.getDetails());
    updateStatement.setBoolean(3, todo.isDone());
    updateStatement.setLong(4, todo.getId());
    updateStatement.executeUpdate();
    readData(connection);
}

Agora você pode descomentar as duas linhas seguintes no método main:

todo.setDetails("congratulations, you have updated data!");
updateData(todo, connection);

A execução da classe principal deve produzir a seguinte saída:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have set up JDBC correctly!', done=true}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have updated data!', done=true}
[INFO   ] Closing database connection

Excluir dados no Azure HorizonDB

Por fim, vamos excluir os dados que inserimos anteriormente.

Ainda no arquivo src/main/java/DemoApplication.java, após o método updateData, adicione o seguinte método para excluir os dados no banco de dados:

private static void deleteData(Todo todo, Connection connection) throws SQLException {
    log.info("Delete data");
    PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM todo WHERE id = ?;");
    deleteStatement.setLong(1, todo.getId());
    deleteStatement.executeUpdate();
    readData(connection);
}

Agora você pode descomentar a seguinte linha no método main:

deleteData(todo, connection);

A execução da classe principal deve produzir a seguinte saída:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: demo
[INFO   ] Create database schema
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have set up JDBC correctly!', done=true}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Todo{id=1, description='configuration', details='congratulations, you have updated data!', done=true}
[INFO   ] Delete data
[INFO   ] Read data
[INFO   ] There is no data in the database!
[INFO   ] Closing database connection

Limpar os recursos

Parabéns! Você criou um aplicativo Java que usa o JDBC para armazenar e recuperar dados de uma instância do Azure HorizonDB.

Para limpar todos os recursos usados durante este início rápido, remova o grupo de recursos usando o seguinte comando:

az group delete \
    --name $AZ_RESOURCE_GROUP \
    --yes