快速入門:使用 Java 和 JDBC for Azure HorizonDB(預覽版)

本文示範如何建立使用 Java 和 JDBC 的範例應用程式,以在 Azure HorizonDB (Preview) 中儲存及擷取資訊。

JDBC 是連接傳統關聯式資料庫的標準 Java API。

本文的步驟包括 PostgreSQL 認證。

PostgreSQL 認證使用儲存在 PostgreSQL 中的帳號,而你需要自己管理密碼的輪替。

先決條件

準備工作環境

首先,使用以下指令來設定一些環境變數。

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>:你在 HorizonDB 叢集Azure中使用的資料庫名稱。
  • <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

如果你是從 Windows 電腦上的 Windows 子系統 Linux 版(WSL)連接到 Azure HorizonDB 叢集,你需要在防火牆上新增 WSL 主機 ID。

透過 WSL 執行以下指令,取得你主機的 IP 位址:

cat /etc/resolv.conf

複製術語 nameserver後面的 IP 位址,然後使用以下指令為 WSL IP 位址設定環境變數:

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 資料庫

建立一個名為 create_database.sql 的 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 非管理員使用者並授予權限

接著,建立一個非管理員使用者,並授予資料庫所有權限。

建立一個名為 create_user.sql 的 SQL 腳本來建立非管理員使用者。 新增以下內容並將檔案儲存在本地:

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 專案

使用你喜愛的 IDE,使用 Java 8 或更新版本建立一個新的 Java 專案。 在根目錄中新增一個包含以下內容的 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
  • 適用於 Java 的最新 PostgreSQL 驅動程式

準備一個設定檔以連接 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 (傳輸層安全性)。 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);

撰寫應用程式程序代碼

連結至資料庫

接著,加入使用 JDBC 來儲存和取回 Azure HorizonDB 實例資料的 Java 程式碼。

建立 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

資料庫認證儲存在 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

建立網域類

在 Todo 類別旁建立新的 DemoApplication Java 類別,並新增下列程式碼:

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

這個類別是在您執行 schema.sqltodo 指令碼時建立的 資料表中對應的領域模型。

將資料插入 Azure HorizonDB

在 src/main/java/DemoApplication.jav 檔案中,在 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);

執行主要類別現在應該會產生下列輸出:

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

執行主要類別現在應該會產生下列輸出:

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

執行主要類別現在應該會產生下列輸出:

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

執行主要類別現在應該會產生下列輸出:

[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

清理資源

祝賀! 你建立了一個使用 JDBC 來儲存和檢索 Azure HorizonDB 實例資料的 Java 應用程式。

若要清理本快速入門期間使用的所有資源,請使用下列命令刪除資源群組:

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