Azure Database for MySQL - 유연한 서버에서 Java 및 JDBC 사용

적용 대상: Azure Database for MySQL - 유연한 서버

이 항목에서는 Java 및 JDBC를 사용하여 Azure Database for MySQL 유연한 서버에 정보를 저장하고 검색하는 애플리케이션 샘플을 만드는 방법을 보여줍니다.

JDBC는 기존 관계형 데이터베이스에 연결하는 표준 Java API입니다.

이 문서에서는 Microsoft Entra 인증 및 MySQL 인증이라는 두 가지 인증 방법을 포함합니다. 암호 없는 탭에는 Microsoft Entra 인증이 표시되고 암호 탭에는 MySQL 인증이 표시됩니다.

Microsoft Entra 인증은 Microsoft Entra ID에 정의된 ID를 사용하여 Azure Database for MySQL 유연한 서버에 연결하는 메커니즘입니다. Microsoft Entra 인증을 사용하면 중앙 위치에서 데이터베이스 사용자 ID 및 기타 Microsoft 서비스를 관리할 수 있으므로 권한 관리가 간소화됩니다.

MySQL 인증은 MySQL에 저장된 계정을 사용합니다. 암호를 계정의 자격 증명으로 사용하도록 선택한 경우 이러한 자격 증명은 user 테이블에 저장됩니다. 이러한 암호는 MySQL에 저장되기 때문에 암호 회전을 직접 관리해야 합니다.

필수 조건

작업 환경 준비

먼저 다음 명령을 사용하여 일부 환경 변수를 설정합니다.

export AZ_RESOURCE_GROUP=database-workshop
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_MYSQL_AD_NON_ADMIN_USERNAME=demo-non-admin
export AZ_USER_IDENTITY_NAME=<YOUR_USER_ASSIGNED_MANAGED_IDENTITY_NAME>
export CURRENT_USERNAME=$(az ad signed-in-user show --query userPrincipalName -o tsv)
export CURRENT_USER_OBJECTID=$(az ad signed-in-user show --query id -o tsv)

자리 표시자를 이 문서 전체에서 사용되는 다음 값으로 바꿉니다.

  • <YOUR_DATABASE_NAME>: Azure Database for MySQL 유연한 서버 인스턴스의 이름으로, Azure 전체에서 고유해야 합니다.
  • <YOUR_AZURE_REGION>: 사용할 Azure 지역. 기본적으로 eastus를 사용할 수 있지만 거주지와 더 가까운 지역을 구성하는 것이 좋습니다. az account list-locations를 입력하면 사용 가능한 지역의 전체 목록을 볼 수 있습니다.
  • <YOUR_USER_ASSIGNED_MANAGED_IDENTITY_NAME>: Azure에서 고유해야 하는 사용자 할당 관리 ID 서버의 이름입니다.

다음으로, 리소스 그룹을 만듭니다.

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

Azure Database for MySQL 인스턴스 만들기

Azure Database for MySQL 유연한 서버 인스턴스 만들기 및 관리 사용자 설정

가장 먼저 만드는 것은 관리형 Azure Database for MySQL 유연한 서버 인스턴스입니다.

참고 항목

MySQL 서버 만들기에 관한 자세한 정보는 Azure Portal을 사용하여 Azure Database for MySQL 유연한 서버 인스턴스 만들기에서 확인할 수 있습니다.

Azure CLI를 사용하는 경우 다음 명령을 실행하여 충분한 권한이 있는지 확인합니다.

az login --scope https://graph.microsoft.com/.default

다음 명령을 실행하여 서버를 만듭니다.

az mysql flexible-server create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME \
    --location $AZ_LOCATION \
    --yes \
    --output tsv

다음 명령을 실행하여 할당할 사용자 할당 ID를 만듭니다.

az identity create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_USER_IDENTITY_NAME

Important

사용자가 할당한 ID를 만든 후 전역 관리자 또는 권한 있는 역할 관리자에게 요청하여 이 ID에 대해 User.Read.All, GroupMember.Read.AllApplication.Read.ALL 권한을 부여합니다. 자세한 내용은 Active Directory 인증권한 섹션을 참조하세요.

다음 명령을 실행하여 Microsoft Entra 관리자를 만들기 위한 Azure Database for MySQL 유연한 서버에 ID를 할당합니다.

az mysql flexible-server identity assign \
    --resource-group $AZ_RESOURCE_GROUP \
    --server-name $AZ_DATABASE_NAME \
    --identity $AZ_USER_IDENTITY_NAME

다음 명령을 실행하여 Microsoft Entra 관리 사용자를 설정합니다.

az mysql flexible-server ad-admin create \
    --resource-group $AZ_RESOURCE_GROUP \
    --server-name $AZ_DATABASE_NAME \
    --display-name $CURRENT_USERNAME \
    --object-id $CURRENT_USER_OBJECTID \
    --identity $AZ_USER_IDENTITY_NAME

Important

관리자를 설정하면 Azure Database for MySQL 유연한 서버 인스턴스에 전체 관리자 권한이 있는 새 사용자가 추가됩니다. Azure Database for MySQL 유연한 서버 인스턴스당 하나의 Microsoft Entra 관리자만 만들 수 있으며 다른 관리자를 선택하면 서버에 대해 구성된 기존 Microsoft Entra 관리자를 덮어씁니다.

이 명령은 작은 Azure Database for MySQL 유연한 서버 인스턴스를 만들고 Active Directory 관리자를 로그인한 사용자로 설정합니다.

만들어진 Azure Database for MySQL 유연한 서버 인스턴스에는 flexibleserverdb라고 하는 빈 데이터베이스가 있습니다.

문제가 있나요? 알려주세요.

Azure Database for MySQL 유연한 서버 인스턴스에 대한 방화벽 규칙 구성

Azure Database for MySQL 유연한 서버 인스턴스는 기본적으로 보호를 받습니다. 들어오는 연결을 허용하지 않는 방화벽이 있습니다.

flexible-server create 명령이 이미 로컬 IP 주소를 감지하고 MySQL 서버에 설정했기 때문에 Bash를 사용하는 경우 이 단계를 건너뛸 수 있습니다.

Windows 시스템의 WSL(Linux용 Windows 하위 시스템)에서 Azure Database for MySQL 유연한 서버 인스턴스에 연결하는 경우 WSL 호스트 ID를 방화벽에 추가해야 합니다. WSL에서 다음 명령을 실행하여 호스트 머신의 IP 주소를 가져옵니다.

sudo cat /etc/resolv.conf

용어 nameserver 다음에 IP 주소를 복사한 다음, 다음 명령을 사용하여 WSL IP 주소에 대한 환경 변수를 설정합니다.

AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

그런 다음, 다음 명령을 사용하여 WSL 기반 앱에 대한 서버의 방화벽을 엽니다.

az mysql flexible-server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME \
    --start-ip-address $AZ_WSL_IP_ADDRESS \
    --end-ip-address $AZ_WSL_IP_ADDRESS \
    --rule-name allowiprange \
    --output tsv

MySQL 데이터베이스 구성

다음 명령을 사용하여 demo라는 새 데이터베이스를 만듭니다.

az mysql flexible-server db create \
    --resource-group $AZ_RESOURCE_GROUP \
    --database-name demo \
    --server-name $AZ_DATABASE_NAME \
    --output tsv

MySQL 관리 사용자가 아닌 사용자 만들기 및 권한 부여

그런 다음 관리 사용자가 아닌 사용자를 만들고 demo 데이터베이스에 대한 모든 권한을 부여합니다.

참고 항목

Azure Database for MySQL에서 사용자 만들기에서 MySQL 사용자 만들기에 대한 자세한 내용을 읽을 수 있습니다.

비관리 사용자를 만들기 위해 create_ad_user.sql이라는 SQL 스크립트를 만듭니다. 다음 콘텐츠를 추가하고 로컬에 저장합니다.

export AZ_MYSQL_AD_NON_ADMIN_USERID=$CURRENT_USER_OBJECTID

cat << EOF > create_ad_user.sql
SET aad_auth_validate_oids_in_tenant = OFF;

CREATE AADUSER '$AZ_MYSQL_AD_NON_ADMIN_USERNAME' IDENTIFIED BY '$AZ_MYSQL_AD_NON_ADMIN_USERID';

GRANT ALL PRIVILEGES ON demo.* TO '$AZ_MYSQL_AD_NON_ADMIN_USERNAME'@'%';

FLUSH privileges;

EOF

그런 다음, 다음 명령을 사용하여 SQL 스크립트를 실행하여 Microsoft Entra 비관리 사용자를 만듭니다.

mysql -h $AZ_DATABASE_NAME.mysql.database.azure.com --user $CURRENT_USERNAME --enable-cleartext-plugin --password=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken) < create_ad_user.sql

이제 다음 명령을 사용하여 임시 SQL 스크립트 파일을 제거합니다.

rm create_ad_user.sql

새 Java 프로젝트 만들기

선호하는 IDE를 사용하여 새 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>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-identity-extensions</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
</project>

이 파일은 다음을 사용하도록 프로젝트를 구성하는 Apache Maven 파일입니다.

  • Java 8
  • Java용 최신 MySQL 드라이버

Azure Database for MySQL에 연결할 구성 파일 준비

프로젝트 루트 디렉터리에서 다음 스크립트를 실행하여 src/main/resources/database.properties 파일을 만들고 구성 세부 정보를 추가합니다.

mkdir -p src/main/resources && touch src/main/resources/database.properties

cat << EOF > src/main/resources/database.properties
url=jdbc:mysql://${AZ_DATABASE_NAME}.mysql.database.azure.com:3306/demo?sslMode=REQUIRED&serverTimezone=UTC&defaultAuthenticationPlugin=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin&authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin
user=${AZ_MYSQL_AD_NON_ADMIN_USERNAME}
EOF

참고 항목

애플리케이션에서 MysqlConnectionPoolDataSource 클래스를 데이터 원본으로 사용하는 경우 URL에서 "defaultAuthenticationPlugin=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin"을 제거하세요.

mkdir -p src/main/resources && touch src/main/resources/database.properties

cat << EOF > src/main/resources/database.properties
url=jdbc:mysql://${AZ_DATABASE_NAME}.mysql.database.azure.com:3306/demo?sslMode=REQUIRED&serverTimezone=UTC&authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin
user=${AZ_MYSQL_AD_NON_ADMIN_USERNAME}
EOF

참고 항목

구성 속성url에는 ?serverTimezone=UTC가 추가되어 데이터베이스에 연결할 때 UTC(협정 세계시) 날짜 형식을 사용하도록 JDBC 드라이버에 지시합니다. 그렇지 않으면 Java 서버에서 데이터베이스와 동일한 날짜 형식을 사용하지 않으므로 오류가 발생합니다.

데이터베이스 스키마를 생성하는 SQL 파일 만들기

데이터베이스 스키마를 만들려면 src/main/resources/schema.sql 파일을 사용합니다. 다음 내용이 포함된 해당 파일을 만듭니다.

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

애플리케이션 코딩

데이터베이스에 연결

다음으로, JDBC를 사용하여 MySQL 서버에서 데이터를 저장하고 검색하는 Java 코드를 추가합니다.

src/main/java/DemoApplication.java 파일을 만들고 다음 콘텐츠를 추가합니다.

package com.example.demo;

import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;

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("database.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();
        AbandonedConnectionCleanupThread.uncheckedShutdown();
    }
}

문제가 있나요? 알려주세요.

이 Java 코드는 Azure Database for MySQL 유연한 서버 인스턴스에 연결하고 데이터를 저장하는 스키마를 만들기 위해 이전에 만든 database.properties 파일과 schema.sql 파일을 사용합니다.

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

참고 항목

데이터베이스 자격 증명은 database.properties 파일의 userpassword 속성에 저장됩니다. 이러한 자격 증명은 속성 파일이 인수로 전달되므로 DriverManager.getConnection(properties.getProperty("url"), properties);를 실행할 때 사용됩니다.

참고 항목

끝에 있는 AbandonedConnectionCleanupThread.uncheckedShutdown(); 줄은 애플리케이션을 종료할 때 내부 스레드를 삭제하는 MySQL 드라이버 전용 명령입니다. 무시해도 됩니다.

이제 즐겨찾는 도구를 사용하여 이 기본 클래스를 실행할 수 있습니다.

  • IDE를 사용하면 DemoApplication 클래스를 마우스 오른쪽 단추로 클릭하여 실행할 수 있어야 합니다.
  • Maven을 통해 mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication"을 실행하여 애플리케이션을 실행할 수 있습니다.

콘솔 로그에 표시되는 것처럼 애플리케이션은 Azure Database for MySQL 유연한 서버 인스턴스에 연결하고 데이터베이스 스키마를 만든 다음 연결을 닫아야 합니다.

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

도메인 클래스 만들기

DemoApplication 클래스 옆에 새 Todo 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.sql 스크립트를 실행할 때 만든 todo 테이블에 매핑된 도메인 모델입니다.

Azure Database for MySQL에 데이터 삽입

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 Database for MySQL에서 데이터 읽기

그런 다음 이전에 삽입한 데이터를 읽어 코드가 올바르게 작동하는지 유효성을 검사합니다.

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 Database for MySQL 유연한 서버에서 데이터 업데이트

다음으로 이전에 삽입한 데이터를 업데이트합니다.

여전히 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 Database for MySQL 유연한 서버에서 데이터 삭제

마지막으로 이전에 삽입한 데이터를 삭제합니다.

여전히 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 Database for MySQL 유연한 서버에서 데이터를 저장하고 검색하는 Java 애플리케이션을 만들었습니다.

이 빠른 시작에서 사용된 모든 리소스를 정리하려면 다음 명령을 사용하여 리소스 그룹을 삭제합니다.

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

다음 단계