Краткое руководство: использование Java и JDBC для Azure HorizonDB (предварительная версия)

В этой статье показано, как создать пример приложения, использующего Java и JDBC для хранения и получения сведений в Azure HorizonDB (предварительная версия).

JDBC — это стандартный API Java для подключения к традиционным реляционным базам данных.

Действия, описанные в этой статье, включают проверку подлинности PostgreSQL.

Проверка подлинности PostgreSQL использует учетные записи, хранящиеся в PostgreSQL, и вам нужно самостоятельно управлять сменой паролей.

Необходимые условия

  • Учетная запись Azure. Если у вас ее нет, получите бесплатную пробную версию.
  • Azure Cloud Shell или Azure CLI Используйте Azure Cloud Shell, чтобы автоматически пройти проверку подлинности и получить доступ ко всем нужным средствам.
  • Поддерживаемый пакет средств разработки Java/c0<> версии 8 (включен в Cloud Shell).
  • Средство сборки Apache Maven.

Подготовка рабочей среды

Сначала используйте следующую команду, чтобы настроить некоторые переменные среды.

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>

Замените заполнители следующими значениями, которые используются в этой статье:

  • <YOUR_DATABASE_CLUSTER_NAME>: Имя вашего кластера Azure HorizonDB, которое должно быть уникальным в пределах вашей подписки Azure и группы ресурсов.
  • <YOUR_DATABASE_NAME>: имя базы данных, используемое в кластере Azure HorizonDB.
  • <YOUR_AZURE_REGION>: регион Azure, который нужно использовать. Вы можете использовать australiaeast по умолчанию, но настроить регион ближе к месту жизни. Полный список доступных регионов можно просмотреть, введя az account list-locations.
  • <YOUR_POSTGRESQL_ADMIN_PASSWORD> и <YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>: пароль кластера Azure HorizonDB. Такой пароль должен содержать не менее восьми символов Символы должны быть из трех из трех следующих категорий: английские прописные буквы, строчные буквы английского языка, цифры (0–9) и нефазные цифры (!, $, #, %, и т. д.).
  • <YOUR_LOCAL_IP_ADDRESS>: IP-адрес локального компьютера, с которого запускается приложение Spring Boot. Один из удобных способов узнать это — открыть whatismyip.akamai.com.

Чтобы создать группу ресурсов, выполните следующую команду:

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

Создание кластера Azure HorizonDB

Note

Не включайте личную, чувствительную или конфиденциальную информацию в имена ресурсов (например, название таблицы, название базы данных) и теги ресурсов. Данные, которые вы вводите в эти поля, не считаются клиентскими данными.

В следующих разделах описывается создание и настройка кластера базы данных.

Создание кластера Azure HorizonDB

Настройка пользователя администратора

Сначала создайте управляемый экземпляр Azure HorizonDB.

Note

Дополнительные сведения о создании кластера Azure HorizonDB см. в разделе Создание кластера 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

Эта команда создает небольшой кластер Azure HorizonDB.

Возникли проблемы? Сообщите нам об этом.

Настройка правила брандмауэра для экземпляра Azure HorizonDB

Экземпляры Azure HorizonDB по умолчанию защищены. У них есть брандмауэр, который блокирует все входящие подключения. Чтобы использовать базу данных, добавьте правило брандмауэра, которое разрешает доступ к серверу базы данных с вашего локального IP-адреса.

Так как вы настроили локальный IP-адрес в начале этой статьи, можно открыть брандмауэр сервера, выполнив следующую команду:

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

Если вы подключаетесь к кластеру Azure HorizonDB из подсистема Windows для Linux (WSL) на компьютере Windows, необходимо добавить идентификатор узла WSL в брандмауэр.

Получите IP-адрес хост-компьютера, выполнив следующую команду в WSL:

cat /etc/resolv.conf

Скопируйте IP-адрес, следующий за термином nameserver, и выполните следующую команду, чтобы задать переменную среды для IP-адреса WSL:

AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

Затем используйте следующую команду, чтобы открыть брандмауэр сервера в приложении на основе 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

Создание базы данных Azure HorizonDB

Создайте скрипт SQL с именем create_database.sql для создания новой базы данных в кластере. Добавьте следующее содержимое и сохраните файл локально:

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

Выполните следующую команду, чтобы получить полное доменное имя Azure HorizonDB и скопируйте значение clusterName:

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

clusterName Скопируйте значение и используйте его в следующей команде:

AZ_HORIZONDB_FQDN=<the-copied-clusterName-value>

Затем выполните следующую команду, чтобы выполнить скрипт SQL и создать базу данных:

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

Теперь выполните следующую команду, чтобы удалить временный файл скрипта SQL:

rm create_database.sql

Создайте пользователя Azure HorizonDB без прав администратора и предоставьте разрешения

Затем создайте пользователя без прав администратора и предоставьте ему все права доступа к базе данных.

Создайте скрипт SQL с именем create_user.sql для создания пользователя, отличного отadmin. Добавьте следующее содержимое и сохраните файл локально:

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

Затем выполните следующую команду, чтобы запустить SQL-скрипт и создать пользователя Microsoft Entra без прав администратора:

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

Теперь выполните следующую команду, чтобы удалить временный файл скрипта SQL:

rm create_user.sql

Создание нового проекта Java

Используя любимую интегрированную среду разработки, создайте проект Java с помощью Java 8 или более поздней версии. Добавьте файлpom.xml в корневой каталог со следующим содержимым:

<?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>

Этот файл — это файл Apache Maven , который настраивает проект для использования:

  • Java 8
  • Последний драйвер PostgreSQL для Java

Подготовка файла конфигурации для подключения к Azure HorizonDB

Создайте файл src/main/resources/application.properties и добавьте следующее содержимое:

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

Свойство url конфигурации включает в себя ?sslmode=require обеспечение того, чтобы драйвер JDBC использовал TLS (transport Layer Security) при подключении к базе данных. для Azure HorizonDB требуется ПРОТОКОЛ TLS, и это рекомендуемая практика безопасности.

Создание SQL-файла для создания схемы базы данных

Используйте файл src/main/resources/schema.sql для создания схемы базы данных. Создайте этот файл со следующим содержимым:

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

Кодирование приложения

Подключение к базе данных

Затем добавьте код Java, использующий JDBC для хранения и извлечения данных из экземпляра Azure HorizonDB.

Создайте файл src/main/java/DemoApplication.java и добавьте следующее содержимое:

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();
    }
}

Возникли проблемы? Сообщите нам об этом.

Этот код Java использует файлы application.properties и файлы schema.sql, созданные ранее, для подключения к экземпляру Azure HorizonDB и создания схемы, в которой хранятся данные.

В этом файле вы увидите, что мы закомментировали методы вставки, чтения, обновления и удаления данных: мы закодируем эти методы в остальной части этой статьи, и вы сможете раскомментировать их друг за другом.

Note

Учетные данные для базы данных хранятся в свойствах user и password в файле application.properties. Эти учетные данные используются при выполнении DriverManager.getConnection(properties.getProperty("url"), properties);, так как файл свойств передается в качестве аргумента.

Теперь вы можете выполнить этот основной класс с помощью вашего любимого инструмента.

  • В любой среде IDE щелкните правой кнопкой мыши класс DemoApplication и выполните его.
  • В Maven приложение можно запустить, выполнив команду mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication".

Приложение должно подключиться к экземпляру Azure HorizonDB, создать схему базы данных, а затем закрыть подключение, как показано в журналах консоли:

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

Создание доменного класса

Создайте новый класс Java Todo рядом с классом DemoApplication и добавьте следующий код:

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 +
                '}';
    }
}

Этот класс является доменной моделью, сопоставленной с таблицей todo, которую вы создали при выполнении скрипта schema.sql.

Вставка данных в Azure HorizonDB

В файле src/main/java/demoapplication.java добавьте после метода main следующий метод, который вставляет данные в базу данных.

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();
}

Теперь можно раскомментировать две следующие строки кода в методе main.

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

Теперь при запуске класса main вы увидите следующие выходные данные.

[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

Чтение данных из Azure HorizonDB

Давайте прочитаем ранее вставленные данные, чтобы убедиться, что наш код работает правильно.

В файле src/main/java/demoapplication.java добавьте после метода insertData следующий метод, который считывает данные из базы данных.

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;
}

Теперь можно раскомментировать следующую строку в методе main.

todo = readData(connection);

Теперь при запуске класса main вы увидите следующие выходные данные.

[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

Обновление данных в Azure HorizonDB

Давайте изменим ранее вставленные данные.

В том же файле src/main/java/demoapplication.java добавьте после метода readData следующий метод, который обновляет данные в базе данных.

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);
}

Теперь можно раскомментировать две следующие строки кода в методе main.

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

Теперь при запуске класса main вы увидите следующие выходные данные.

[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

Удаление данных в Azure HorizonDB

Наконец, давайте удалим ранее вставленные данные.

В том же файле src/main/java/demoapplication.java добавьте после метода updateData следующий метод, который удаляет данные из базы данных.

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);
}

Теперь можно раскомментировать следующую строку в методе main.

deleteData(todo, connection);

Теперь при запуске класса main вы увидите следующие выходные данные.

[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

Очистите ресурсы

Поздравляем! Вы создали приложение Java, использующее JDBC для хранения и извлечения данных из экземпляра HorizonDB Azure.

Чтобы удалить все ресурсы, использованные в ходе быстрого запуска, удалите группу ресурсов с помощью следующей команды.

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