Azure Database for MySQL - フレキシブル サーバーで Java と JDBC を使用する
この記事では、Java と JDBC を使って Azure Database for MySQL フレキシブル サーバーに情報を格納および取得するサンプル アプリケーションを作成する方法を説明します。
JDBC は、従来のリレーショナル データベースに接続するための標準の Java API です。
この記事には、Microsoft Entra 認証と MySQL 認証の 2 つの認証方法が含まれています。 [パスワードレス] タブには Microsoft Entra 認証が表示され、[パスワード] タブには MySQL 認証が表示されます。
Microsoft Entra 認証は、Microsoft Entra ID で定義された ID を使用して Azure Database for MySQL フレキシブル サーバーに接続するためのメカニズムです。 Microsoft Entra 認証を使用すると、データベース ユーザーの ID や他の Microsoft サービスを一元管理でき、アクセス許可の管理が容易になります。
MySQL 認証では、MySQL に格納されているアカウントが使用されます。 アカウントの資格情報としてパスワードを使用することを選択した場合、これらの資格情報は user
テーブルに格納されます。 これらのパスワードは MySQL に格納されるため、パスワードのローテーションを自分で管理する必要があります。
前提条件
- アクティブなサブスクリプションが含まれる Azure アカウント。
Azure サブスクリプションをお持ちでない場合は、開始する前に Azure 無料アカウントを作成してください。 現在、Azure 無料アカウントがあれば、Azure Database for MySQL - フレキシブル サーバーを 12 か月間無料でお試しいただけます。 詳細については、「Azure 無料アカウントを使用して Azure Database for MySQL - フレキシブル サーバーを無料で試す」を参照してください。
- 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>
: Azure Database for MySQL フレキシブル サーバーの名前。これは、Azure 全体で一意である必要があります。<YOUR_AZURE_REGION>
:使用する Azure リージョン。 既定でeastus
を使用できますが、居住地に近いリージョンを構成することをお勧めします。az account list-locations
と入力すると、使用可能なリージョンの一覧全体を表示できます。<YOUR_USER_ASSIGNED_MANAGED_IDENTITY_NAME>
: ユーザー割り当てマネージド ID サーバーの名前。Azure 全体で一意である必要があります。
次に、リソース グループを作成します。
az group create \
--name $AZ_RESOURCE_GROUP \
--location $AZ_LOCATION \
--output tsv
Azure Database for MySQL インスタンスを作成する
Azure Database for MySQL フレキシブル サーバー インスタンスを作成し、管理者ユーザーを設定する
最初に作成するのは、マネージド Azure Database for MySQL フレキシブル サーバー インスタンスです。
Note
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
重要
ユーザー割り当て ID を作成したら、少なくとも特権ロール管理者ロールを持つユーザーに、このユーザー割り当てマネージド ID に対して次のアクセス許可を付与するように依頼します: User.Read.All
、GroupMember.Read.All
、および Application.Read.ALL
。 または、ユーザー割り当てマネージド ID にディレクトリ閲覧者ロールを付与します。 詳細については、「Azure Database for MySQL - フレキシブル サーバーの Microsoft Entra 認証」の「アクセス許可」セクションを参照してください。
次のコマンドを実行して、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
重要
管理者を設定すると、管理者の完全なアクセス許可を持つ新しいユーザーが Azure Database for MySQL フレキシブル サーバーに追加されます。 作成できる Microsoft Entra 管理者は、Azure Database for MySQL フレキシブル サーバー インスタンスあたり 1 人だけです。別の管理者を選択すると、そのサーバーに構成されている既存の Microsoft Entra 管理者が上書きされます。
このコマンドにより、小さな Azure Database for MySQL フレキシブル サーバー インスタンスが作成され、サインインしているユーザーに Active Directory 管理者が設定されます。
作成した Azure Database for MySQL フレキシブル サーバー インスタンスには、flexibleserverdb
という名前の空のデータベースがあります。
Azure Database for MySQL フレキシブル サーバー インスタンスのファイアウォール規則を構成する
Azure Database for MySQL フレキシブル サーバー インスタンスは、既定でセキュリティ保護されています。 受信接続を一切許可しないファイアウォールがあります。
Bash を使用している場合は、flexible-server create
コマンドによってローカル IP アドレスが既に検出され、MySQL サーバーに設定されているため、この手順はスキップできます。
Windows コンピューター上の Linux 用 Windows サブシステム (WSL) から 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
データベースに対するすべてのアクセス許可を付与します。
Note
MySQL ユーザーの作成の詳細については、Azure Database for MySQL でのユーザーの作成に関するページを参照してください。
非管理者ユーザーを作成するための 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 ドライバー
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
Note
アプリケーションでデータソースとして 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
Note
構成プロパティ 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 ファイルを使用します。
このファイルを見るとわかるように、データの挿入、読み取り、更新、削除のためのメソッドがコメント化されています。これらのメソッドのコードは、この記事の中で後から作成します。それぞれのメソッドが完成したら都度、コメント解除することができます。
Note
データベースの資格情報は、database.properties ファイルの user と password プロパティに格納されます。 プロパティ ファイルは引数として渡されるため、これらの資格情報は DriverManager.getConnection(properties.getProperty("url"), properties);
を実行するときに使用されます。
Note
末尾の 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 ファイルの 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
メソッドの次の 2 つの行のコメントを解除できます。
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
メソッドの次の 2 つの行のコメントを解除できます。
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