搭配使用 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 個月。 如需詳細資訊,請參閱使用 Azure 免費帳戶免費試用 適用於 MySQL 的 Azure 資料庫 - 彈性伺服器。
- Azure Cloud Shell 或 Azure 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
重要
建立使用者指派的身分識別之後,請要求至少 具有特殊許可權角色管理員 角色的使用者授與此使用者指派的受控識別下列許可權: User.Read.All
、 GroupMember.Read.All
和 Application.Read.ALL
。 或者,為使用者指派的受控識別 提供目錄讀取者 角色。 如需詳細資訊,請參閱 Microsoft 適用於 MySQL 的 Azure 資料庫 - 彈性伺服器之 Entra 驗證的許可權一節。
執行下列命令,將身分識別指派給 適用於 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 使用者的更多詳細資訊,請參閱在適用於 MySQL 的 Azure 資料庫中建立使用者。
建立名為 create_ad_user.sql 的 SQL 指令碼,以建立非管理使用者。 新增下列內容,並將其儲存在本地:
export AZ_MYSQL_AD_NON_ADMIN_USERID=$(az ad signed-in-user show --query id --output tsv)
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
注意
如果您要在應用程式中使用 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
,以指示 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 的 Java 程式碼,以從您的 MySQL 伺服器儲存和擷取資料。
建立 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.properties 和 schema.sql 檔案,以連線到 適用於 MySQL 的 Azure 資料庫 彈性伺服器實例,並建立將儲存數據的架構。
在此檔案中,您可以看到我們已針對插入、讀取、更新和刪除資料的方法加上註解,並在本文的其他部分撰寫這些方法的程式碼,讓您能夠逐一取消這些方法的註解。
注意
資料庫認證會儲存在 database.properties 檔案的 user 和 password 屬性中。 這些認證會在執行 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.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
從 適用於 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);
執行主要類別現在應該會產生下列輸出:
[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);
執行主要類別現在應該會產生下列輸出:
[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);
執行主要類別現在應該會產生下列輸出:
[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 從 適用於 MySQL 的 Azure 資料庫 彈性伺服器儲存和擷取數據的 Java 應用程式。
若要清除在此快速入門期間使用的所有資源,請使用下列命令刪除資源群組:
az group delete \
--name $AZ_RESOURCE_GROUP \
--yes