Szybki start: używanie Java i JDBC dla Azure HorizonDB (wersja zapoznawcza)

W tym artykule pokazano, jak utworzyć przykładową aplikację, która używa Java i JDBC do przechowywania i pobierania informacji w Azure HorizonDB (wersja zapoznawcza).

JDBC to standardowy interfejs API Java do nawiązywania połączenia z tradycyjnymi relacyjnymi bazami danych.

Kroki opisane w tym artykule obejmują uwierzytelnianie postgreSQL.

Uwierzytelnianie postgreSQL używa kont przechowywanych w usłudze PostgreSQL i musisz samodzielnie zarządzać rotacją haseł.

Wymagania wstępne

Przygotowywanie środowiska roboczego

Najpierw użyj następującego polecenia, aby skonfigurować niektóre zmienne środowiskowe.

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>

Zastąp symbole zastępcze następującymi wartościami, które są używane w tym artykule:

  • <YOUR_DATABASE_CLUSTER_NAME>: nazwa klastra Azure HorizonDB, który powinien być unikatowy w ramach subskrypcji Azure i grupy zasobów.
  • <YOUR_DATABASE_NAME>: nazwa bazy danych używana w klastrze Azure HorizonDB.
  • <YOUR_AZURE_REGION>: region świadczenia usługi Azure do użycia. Możesz użyć australiaeast domyślnie, ale skonfigurować region bliżej miejsca, w którym mieszkasz. Pełną listę dostępnych regionów można wyświetlić, wprowadzając polecenie az account list-locations.
  • <YOUR_POSTGRESQL_ADMIN_PASSWORD> i <YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>: hasło klastra Azure HorizonDB. To hasło powinno zawierać co najmniej osiem znaków. Znaki powinny pochodzić z trzech z następujących kategorii: wielkie litery angielskie, małe litery angielskie, cyfry (0–9) i znaki niefanumeryczne (!, $, #, %itd.).
  • <YOUR_LOCAL_IP_ADDRESS>: adres IP komputera lokalnego, z którego jest uruchamiana aplikacja Spring Boot. Jednym z wygodnych sposobów znalezienia jest otwarcie whatismyip.akamai.com.

Następnie utwórz grupę zasobów przy użyciu następującego polecenia:

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

Tworzenie klastra Azure HorizonDB

Note

Nie umieszczaj żadnych danych osobowych, wrażliwych ani poufnych w nazwach zasobów (na przykład w nazwie tabeli, nazwie bazy danych) ani w tagach zasobów. Dane wpisywane w tych polach nie są traktowane jako dane klienta.

W poniższych sekcjach opisano sposób tworzenia i konfigurowania klastra bazy danych.

Tworzenie klastra Azure HorizonDB

Konfigurowanie użytkownika administratora

Najpierw utwórz wystąpienie zarządzane Azure HorizonDB.

Note

Aby uzyskać bardziej szczegółowe informacje na temat tworzenia bazy danych Azure HorizonDB, zobacz Tworzenie klastra 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

To polecenie tworzy mały klaster Azure HorizonDB.

Masz jakieś problemy? Daj nam znać.

Skonfiguruj regułę zapory dla Twojego wystąpienia Azure HorizonDB

Wystąpienia usługi Azure HorizonDB są domyślnie bezpieczne. Mają zaporę, która blokuje wszystkie połączenia przychodzące. Aby korzystać z bazy danych, dodaj regułę zapory, która umożliwia lokalnemu adresowi IP dostęp do serwera bazy danych.

Ponieważ na początku tego artykułu skonfigurowano lokalny adres IP, możesz otworzyć zaporę serwera, uruchamiając następujące polecenie:

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

Jeśli łączysz się z klastrem Azure HorizonDB z poziomu Podsystem Windows dla systemu Linux (WSL) na komputerze z systemem Windows, musisz dodać identyfikator hosta WSL do zapory sieciowej.

Pobierz adres IP maszyny hosta, uruchamiając następujące polecenie w programie WSL:

cat /etc/resolv.conf

Skopiuj adres IP zgodny z terminem nameserver, a następnie użyj następującego polecenia, aby ustawić zmienną środowiskową dla adresu IP WSL:

AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

Następnie użyj następującego polecenia, aby otworzyć zaporę serwera w aplikacji opartej na protokole 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

Tworzenie bazy danych Azure HorizonDB

Utwórz skrypt SQL o nazwie create_database.sql , aby utworzyć nową bazę danych w klastrze. Dodaj następującą zawartość i zapisz plik lokalnie:

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

Uruchom to polecenie, aby uzyskać w pełni kwalifikowaną nazwę domeny Azure HorizonDB i skopiować wartość clusterName:

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

clusterName Skopiuj wartość i użyj jej w następującym poleceniu:

AZ_HORIZONDB_FQDN=<the-copied-clusterName-value>

Następnie uruchom następujące polecenie, aby wykonać skrypt SQL i utworzyć bazę danych:

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

Teraz uruchom następujące polecenie, aby usunąć tymczasowy plik skryptu SQL:

rm create_database.sql

Tworzenie użytkownika niebędącego administratorem usługi Azure HorizonDB i udzielanie uprawnień

Następnie utwórz użytkownika niebędącego administratorem i przyznaj wszystkie uprawnienia do bazy danych.

Utwórz skrypt SQL o nazwie create_user.sql , aby utworzyć użytkownika niebędącego administratorem. Dodaj następującą zawartość i zapisz plik lokalnie:

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

Następnie uruchom następujące polecenie, aby wykonać skrypt SQL i utworzyć Microsoft Entra użytkownika niebędącego administratorem:

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

Teraz uruchom następujące polecenie, aby usunąć tymczasowy plik skryptu SQL:

rm create_user.sql

Tworzenie nowego projektu Java

Używając ulubionego środowiska IDE, utwórz nowy projekt Java przy użyciu Java 8 lub nowszego. Dodaj plik pom.xml w katalogu głównym z następującą zawartością:

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

Ten plik jest plikiem Apache Maven , który konfiguruje projekt do użycia:

  • Java 8
  • Najnowszy sterownik PostgreSQL dla języka Java

Przygotowywanie pliku konfiguracji do nawiązania połączenia z usługą Azure HorizonDB

Utwórz plik src/main/resources/application.properties i dodaj następującą zawartość:

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

Właściwość konfiguracji url zawiera ?sslmode=require, aby upewnić się, że sterownik JDBC korzysta z protokołu TLS (Transport Layer Security) podczas łączenia się z bazą danych. Azure HorizonDB wymaga protokołu TLS i jest to zalecana praktyka zabezpieczeń.

Tworzenie pliku SQL w celu wygenerowania schematu bazy danych

Utwórz schemat bazy danych za pomocą pliku src/main/resources/schema.sql . Utwórz ten plik z następującą zawartością:

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

Kodowanie aplikacji

Łączenie z bazą danych

Następnie dodaj kod Java, który używa narzędzia JDBC do przechowywania i pobierania danych z wystąpienia usługi Azure HorizonDB.

Utwórz plik src/main/java/DemoApplication.java i dodaj następującą zawartość:

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

Masz jakieś problemy? Daj nam znać.

Ten kod Java używa utworzonych wcześniej plików application.properties i schema.sql, aby nawiązać połączenie z wystąpieniem Azure HorizonDB i utworzyć schemat przechowujący dane.

W tym pliku zobaczysz, że skomentowaliśmy metody wstawiania, odczytywania, aktualizowania i usuwania danych: zakodujemy te metody w pozostałej części tego artykułu i będziesz w stanie usunąć ich komentarz po sobie.

Note

Poświadczenia bazy danych są przechowywane we właściwościach użytkownika i hasła pliku application.properties. Te dane uwierzytelniające są używane podczas uruchamiania DriverManager.getConnection(properties.getProperty("url"), properties);, ponieważ plik właściwości jest przekazywany jako argument.

Teraz możesz wykonać tę klasę główną za pomocą ulubionego narzędzia:

  • Za pomocą swojego środowiska IDE powinieneś być w stanie kliknąć prawym przyciskiem myszy na klasę DemoApplication i uruchomić ją.
  • Za pomocą narzędzia Maven możesz uruchomić aplikację, wykonując polecenie: mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication".

Aplikacja powinna nawiązać połączenie z wystąpieniem usługi Azure HorizonDB, utworzyć schemat bazy danych, a następnie zamknąć połączenie, jak pokazano w dziennikach konsoli:

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

Tworzenie klasy domeny

Utwórz nową Todo klasę Java obok DemoApplication klasy i dodaj następujący kod:

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

Ta klasa jest modelem domeny zamapowanym na tabelę todo utworzoną podczas wykonywania skryptu schema.sql .

Wstawianie danych do Azure HorizonDB

W pliku src/main/java/DemoApplication.java po metodzie main dodaj następującą metodę, aby wstawić dane do bazy danych:

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

Teraz możesz odkomentować dwa następujące wiersze w metodzie main :

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

Wykonanie klasy głównej powinno teraz wygenerować następujące dane wyjściowe:

[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

Odczytywanie danych z Azure HorizonDB

Przeczytajmy wcześniej wstawione dane, aby sprawdzić, czy nasz kod działa poprawnie.

W pliku src/main/java/DemoApplication.java po metodzie insertData dodaj następującą metodę, aby odczytać dane z bazy danych:

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

Teraz możesz usunąć komentarz z następującego wiersza w metodzie main :

todo = readData(connection);

Wykonanie klasy głównej powinno teraz wygenerować następujące dane wyjściowe:

[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

Aktualizowanie danych w usłudze Azure HorizonDB

Zaktualizujmy dane, które wcześniej wstawiliśmy.

Nadal w pliku src/main/java/DemoApplication.java po metodzie readData dodaj następującą metodę, aby zaktualizować dane wewnątrz bazy danych:

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

Teraz możesz odkomentować dwa następujące wiersze w metodzie main :

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

Wykonanie klasy głównej powinno teraz wygenerować następujące dane wyjściowe:

[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

Usuwanie danych w usłudze Azure HorizonDB

Na koniec usuńmy wcześniej wstawione dane.

Nadal w pliku src/main/java/DemoApplication.java po metodzie updateData dodaj następującą metodę, aby usunąć dane wewnątrz bazy danych:

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

Teraz możesz usunąć komentarz z następującego wiersza w metodzie main :

deleteData(todo, connection);

Wykonanie klasy głównej powinno teraz wygenerować następujące dane wyjściowe:

[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

Uprzątnij zasoby

Gratulacje! Utworzono aplikację Java, która używa narzędzia JDBC do przechowywania i pobierania danych z wystąpienia usługi Azure HorizonDB.

Aby wyczyścić wszystkie zasoby używane w tej instrukcji szybkiego startu, usuń grupę zasobów, używając następującego polecenia:

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