빠른 시작: Azure HorizonDB에 Java 및 JDBC 사용(미리 보기)

이 문서에서는 Java 및 JDBC를 사용하여 Azure HorizonDB(미리 보기) 정보를 저장하고 검색하는 샘플 애플리케이션을 만드는 방법을 보여 줍니다.

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 구독 및 리소스 그룹에서 고유해야 하는 Azure HorizonDB 클러스터의 이름입니다.
  • <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 클러스터의 암호입니다. 암호의 길이는 8자 이상이어야 합니다. 문자는 영어 대문자, 영어 소문자, 숫자(0-9) 및 영숫자가 아닌 문자(!, $, #, % 등) 중 세 가지 범주에 속해야 합니다.
  • <YOUR_LOCAL_IP_ADDRESS>: Spring Boot 애플리케이션을 실행하는 로컬 컴퓨터의 IP 주소입니다. 한 가지 편리한 방법은 whatismyip.akamai.com 여는 것입니다.

다음으로, 다음 명령을 사용하여 리소스 그룹을 만듭니다.

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

Azure HorizonDB 클러스터 만들기

메모

리소스 이름(예: 테이블 이름, 데이터베이스 이름)과 리소스 태그에 개인적이거나 민감한 정보, 기밀 정보를 포함하지 마세요. 이 필드에 입력한 데이터는 고객 데이터로 간주되지 않습니다.

다음 섹션에서는 데이터베이스 클러스터를 만들고 구성하는 방법을 설명합니다.

Azure HorizonDB 클러스터 만들기

관리자 사용자 설정

먼저 관리되는 Azure HorizonDB 인스턴스를 만듭니다.

메모

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 컴퓨터의 Linux용 Windows 하위 시스템(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 nonadmin 사용자 만들기 및 권한 부여

다음으로, nonadmin 사용자를 만들고 데이터베이스에 모든 권한을 부여합니다.

create_user.sql 명명된 SQL 스크립트를 만들어 nonadmin 사용자를 만듭니다. 다음 콘텐츠를 추가하고 파일을 로컬로 저장합니다.

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 nonadmin 사용자를 만듭니다.

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

메모

구성 속성 url 에는 JDBC 드라이버가 데이터베이스에 연결할 때 TLS(전송 계층 보안)를 사용하는지 확인하는 것이 포함됩니다 ?sslmode=require . 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 인스턴스에 연결하고 데이터를 저장하는 스키마를 만듭니다.

이 파일에서는 데이터를 삽입, 읽기, 업데이트 및 삭제하는 메서드를 주석으로 처리한 것을 볼 수 있습니다. 이 문서의 나머지 부분에 해당 메서드를 코딩하고 서로 주석 처리를 해제할 수 있습니다.

메모

데이터베이스 자격 증명은 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 +
                '}';
    }
}

이 클래스는 todo 스크립트를 실행할 때 만든 테이블에 매핑된 도메인 모델입니다.

Azure HorizonDB에 데이터 삽입

src/main/java/DemoApplication.java 파일에서 주 메서드 뒤에 다음 메서드를 추가하여 데이터를 데이터베이스에 삽입합니다.

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