Share via


搭配 適用於 MySQL 的 Azure 資料庫 使用 Java 和 JDBC - 彈性伺服器

適用於:適用於 MySQL 的 Azure 資料庫 - 彈性伺服器

本主題示範如何建立範例應用程式,以使用Java和JDBC在 適用於 MySQL 的 Azure 資料庫彈性伺服器儲存和擷取資訊。

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

在本文中,我們將包含兩種驗證方法:Microsoft Entra 驗證和 MySQL 驗證。 [無密碼] 索引標籤會顯示 Microsoft Entra 驗證,而 [密碼] 索引標籤會顯示 MySQL 驗證。

Microsoft Entra 驗證是一種機制,可使用 Microsoft Entra 識別碼中定義的身分識別連線到 適用於 MySQL 的 Azure 資料庫 彈性伺服器。 透過 Microsoft Entra 驗證,您可以在中央位置管理資料庫使用者身分識別和其他 Microsoft 服務,以簡化許可權管理。

MySQL 驗證會使用儲存在 MySQL 中的帳戶。 如果您選擇使用密碼作為帳戶的認證,這些認證會儲存在數據表中 user 。 因為這些密碼會儲存在 MySQL 中,因此您必須自行管理密碼的輪替。

必要條件

  • 具有作用中訂用帳戶的 Azure 帳戶。如果您沒有 Azure 訂用帳戶,請在開始之前建立 Azure 免費帳戶 。 目前,使用 Azure 免費帳戶,您可以免費試用 適用於 MySQL 的 Azure 資料庫 - 彈性伺服器 12 個月。 如需詳細資訊,請參閱免費試用 適用於 MySQL 的 Azure 資料庫 - 彈性伺服器。
  • Azure Cloud ShellAzure CLI。 我們建議使用 Azure Cloud Shell,以便自動登入並存取所需的所有工具。
  • 支援的 Java 開發套件第 8 版 (包含在 Azure Cloud Shell 中)。
  • Apache Maven 建置工具。

準備工作環境

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

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>:您 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例的名稱,在 Azure 中應該是唯一的。
  • <YOUR_AZURE_REGION>:您將使用的 Azure 區域。 根據預設,您可以使用 eastus,但建議您設定為居住地附近的區域。 您可以輸入 az account list-locations來檢視可用區域的完整清單。
  • <YOUR_USER_ASSIGNED_MANAGED_IDENTITY_NAME>:使用者指派的受控識別伺服器名稱,在 Azure 中應該是唯一的。

接著,建立資源群組:

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

建立適用於 MySQL 的 Azure 資料庫執行個體

建立 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例並設定系統管理員使用者

您建立的第一件事是受控 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例。

注意

您可以在使用 Azure 入口網站 建立 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例中,閱讀建立 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

執行下列命令,以建立使用者指派的身分識別以進行指派:

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

重要

建立使用者指派的身分識別之後,請要求全域 管理員 istrator 或 Privileged Role 管理員 istrator 授與此身分識別的下列許可權:User.Read.AllGroupMember.Read.AllApplication.Read.ALL。 如需詳細資訊,請參閱 Active Directory 驗證的許可權一節。

執行下列命令,將身分識別指派給 適用於 MySQL 的 Azure 資料庫 彈性伺服器,以建立 Microsoft Entra 系統管理員:

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

重要

設定系統管理員時,會將新的使用者新增至具有完整系統管理員許可權的 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例。 每個 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例只能建立一個 Microsoft Entra 系統管理員,而另一個管理員的選取專案將會覆寫針對伺服器設定的現有 Microsoft Entra 系統管理員。

此命令會建立小型 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例,並將 Active Directory 系統管理員設定為已登入的使用者。

您所建立的 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例具有名為 的flexibleserverdb空白資料庫。

發生任何問題嗎? 讓我們知道。

為您的 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例設定防火牆規則

適用於 MySQL 的 Azure 資料庫 彈性伺服器實例預設會受到保護。 它們具有不允許任何連入連線的防火牆。

如果您使用 Bash,您可以略過此步驟,因為 flexible-server create 命令已經偵測到本機 IP 位址,並在 MySQL 伺服器上設定它。

如果您要從 Windows 電腦上的 Windows 子系統 Linux 版 (WSL) 連線到 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例,您必須將 WSL 主機標識元新增至防火牆。 在 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 授與資料庫。

注意

您可以在在 適用於 MySQL 的 Azure 資料庫 中建立使用者中,閱讀有關建立 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 驅動程式

準備組態檔以連線至 適用於 MySQL 的 Azure 資料庫

在專案根目錄中執行下列腳本,以建立 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

注意

如果您使用 Mysql 連線 ionPoolDataSource 類別作為應用程式中的數據源,請在 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 附加,以告知 JDBC 驅動程式在連線到資料庫時使用 UTC 日期格式(或國際標準時間)。 否則,您的 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 程式代碼會使用您稍早建立的 database.propertiesschema.sql 檔案,以連線到 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例,並建立將儲存數據的架構。

在此檔案中,您可以看到我們已加上批注的方法來插入、讀取、更新和刪除數據:您將在本文的其餘部分撰寫這些方法的程序代碼,而且您可以彼此取消批注。

注意

資料庫認證會儲存在 database.properties 檔案的使用者密碼屬性中。 執行 DriverManager.getConnection(properties.getProperty("url"), properties); 時會使用這些認證,因為屬性檔案會作為引數傳遞。

注意

結尾的 AbandonedConnectionCleanupThread.uncheckedShutdown(); 行是 MySQL 驅動程式特定的命令,會在關閉應用程式時終結內部線程。 可以放心地忽略它。

您現在可以使用慣用的工具來執行此主要類別:

  • 使用 IDE 時,您應該能夠以滑鼠右鍵按一下 DemoApplication 類別並執行它。
  • 使用 Maven 時,您可以藉由執行 mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication" 來執行應用程式。

應用程式應該連線到 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例、建立資料庫架構,然後關閉連線,如控制台記錄中所見:

[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 資料表上的領域模型。

將數據插入 適用於 MySQL 的 Azure 資料庫

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

從 適用於 MySQL 的 Azure 資料庫 讀取數據

接下來,讀取先前插入的數據,以驗證您的程式代碼是否正常運作。

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

發生任何問題嗎? 讓我們知道。

更新 適用於 MySQL 的 Azure 資料庫 彈性伺服器中的數據

接下來,更新您先前插入的數據。

仍然在 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

刪除 適用於 MySQL 的 Azure 資料庫 彈性伺服器中的數據

最後,刪除您先前插入的數據。

仍然在 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 從 適用於 MySQL 的 Azure 資料庫 彈性伺服器儲存和擷取數據。

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

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

下一步