Condividi tramite


Usare Java e JDBC con Database di Azure per MySQL - Server flessibile

SI APPLICA A: Database di Azure per MySQL - Server flessibile

Questo argomento illustra la creazione di un'applicazione di esempio che usa Java e JDBC per archiviare e recuperare informazioni in Database di Azure per MySQL server flessibile.

JDBC è l'API Java standard per la connessione ai database relazionali tradizionali.

In questo articolo verranno inclusi due metodi di autenticazione: autenticazione Microsoft Entra e autenticazione MySQL. La scheda Senza password mostra l'autenticazione Microsoft Entra e la scheda Password l'autenticazione mySQL.

L'autenticazione di Microsoft Entra è un meccanismo per la connessione a Database di Azure per MySQL server flessibile usando le identità definite in Microsoft Entra ID. Con l'autenticazione Microsoft Entra è possibile gestire centralmente le identità degli utenti del database e di altri servizi Microsoft semplificando la gestione delle autorizzazioni.

L'autenticazione mySQL usa gli account archiviati in MySQL. Se si sceglie di usare password come credenziali per gli account, queste credenziali verranno archiviate nella tabella user. Poiché queste password vengono archiviate in MySQL, è necessario gestire manualmente la rotazione delle password.

Prerequisiti

Preparare l'ambiente di lavoro

Prima, configurare alcune variabili di ambiente usando il comando seguente.

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)

Sostituire i segnaposto con i valori seguenti, che vengono usati nell'intero articolo:

  • <YOUR_DATABASE_NAME>: nome dell'istanza del server flessibile Database di Azure per MySQL, che deve essere univoco in Azure.
  • <YOUR_AZURE_REGION>: l'area di Azure da usare. È possibile usare eastus per impostazione predefinita, ma è consigliabile configurare un'area più vicina a dove si risiede. Per visualizzare l'elenco completo di aree disponibili, immettere az account list-locations.
  • <YOUR_USER_ASSIGNED_MANAGED_IDENTITY_NAME>: nome del server di identità gestito assegnato dall'utente, che deve essere univoco in Azure.

Successivamente, creare un gruppo di risorse:

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

Creare un'istanza di Database di Azure per MySQL

Creare Database di Azure per MySQL'istanza del server flessibile e configurare un utente amministratore

La prima cosa che si crea è un'istanza del server flessibile gestita Database di Azure per MySQL.

Nota

Per altre informazioni dettagliate sulla creazione di server MySQL, vedere Creare un'istanza del server flessibile di Database di Azure per MySQL usando il portale di Azure.

Se è in uso l'interfaccia della riga di comando di Azure, eseguire il comando seguente per assicurarsi che disponga di autorizzazioni sufficienti:

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

Eseguire il comando seguente per creare il server:

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

Eseguire il comando seguente per creare un'identità assegnata dall'utente per l'assegnazione:

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

Importante

Dopo aver creato l'identità assegnata dall'utente, chiedere a un utente con almeno il ruolo Di amministratore ruolo con privilegi di concedere le autorizzazioni seguenti per questa identità gestita assegnata dall'utente: User.Read.All, GroupMember.Read.Alle Application.Read.ALL. In alternativa, assegnare all'identità gestita assegnata dall'utente il ruolo Lettori directory. Per altre informazioni, vedere la sezione Autorizzazioni in Autenticazione di Active Directory.

Eseguire il comando seguente per assegnare l'identità a Database di Azure per MySQL server flessibile per la creazione dell'amministratore di Microsoft Entra:

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

Eseguire il comando seguente per impostare l'utente amministratore di 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

Importante

Quando si imposta l'amministratore, viene aggiunto un nuovo utente all'istanza del server flessibile Database di Azure per MySQL con autorizzazioni di amministratore completo. È possibile creare un solo amministratore di Microsoft Entra per Database di Azure per MySQL'istanza del server flessibile e la selezione di un'altra sovrascriverà l'amministratore esistente di Microsoft Entra configurato per il server.

Questo comando crea una piccola istanza del server flessibile di Database di Azure per MySQL e imposta l'amministratore di Active Directory sull'utente connesso.

L'istanza del server flessibile Database di Azure per MySQL creata ha un database vuoto denominato flexibleserverdb.

Problemi? Segnalarli.

Configurare una regola del firewall per l'istanza del server flessibile Database di Azure per MySQL

Database di Azure per MySQL istanze del server flessibile sono protette per impostazione predefinita. Includono un firewall che non consente alcuna connessione in ingresso.

È possibile ignorare questo passaggio se si usa Bash perché il comando ha già rilevato l'indirizzo flexible-server create IP locale e impostarlo nel server MySQL.

Se ci si connette all'istanza del server flessibile Database di Azure per MySQL da sottosistema Windows per Linux (WSL) in un computer Windows, è necessario aggiungere l'ID host WSL al firewall. Ottenere l'indirizzo IP del computer host eseguendo il comando seguente in WSL:

sudo cat /etc/resolv.conf

Copiare l'indirizzo IP seguendo il termine nameserver, quindi usare il comando seguente per impostare una variabile di ambiente per l'indirizzo IP WSL:

AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

Usare quindi il comando seguente per aprire il firewall del server all'app basata su 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

Configurare un database MySQL

Creare un nuovo database denominato demo con il comando seguente:

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

Creare un utente non amministratore di MySQL e concedere l'autorizzazione

Creare quindi un utente non amministratore e concedere tutte le autorizzazioni per il demo database.

Nota

Per altre informazioni dettagliate sulla creazione di utenti MySQL, vedere Creare utenti in Database di Azure per MySQL.

Creare uno script SQL denominato create_ad_user.sql per la creazione di un utente non amministratore. Aggiungervi il contenuto seguente e salvarlo in locale:

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

Quindi, usare il comando seguente per eseguire lo script SQL per creare l'utente non amministratore di 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

A questo punto, usare il comando seguente per rimuovere il file di script SQL temporaneo:

rm create_ad_user.sql

Creare un nuovo progetto Java

Usando l'IDE preferito, creare un nuovo progetto Java e aggiungere un file pom.xml nella directory radice:

<?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>

Questo file è un file Apache Maven che configura il progetto da usare:

  • Java 8
  • Un driver di MySQL recente per Java

Preparare un file di configurazione per la connessione a Database di Azure per MySQL

Eseguire lo script seguente nella directory radice del progetto per creare un file src/main/resources/database.properties e aggiungere dettagli di configurazione:

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

Nota

Se si usa la classe MysqlConnectionPoolDataSource come origine dati nell'applicazione, rimuovere "defaultAuthenticationPlugin=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin" dall'URL.

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

Nota

Alla proprietà di configurazione url viene aggiunto ?serverTimezone=UTC per indicare al driver JDBC di usare il formato di data UTC (o Coordinated Universal Time) durante la connessione al database. In caso contrario, il server Java non userà lo stesso formato di data del database, causando un errore.

Creare un file SQL per generare lo schema del database

Si userà un file src/main/resources/schema.sql per creare uno schema di database. Creare tale file con il contenuto seguente:

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

Codice dell'applicazione

Stabilire la connessione al database

Aggiungere quindi il codice Java che userà JDBC per archiviare e recuperare i dati dal server MySQL.

Creare un file src/main/java/DemoApplication.java e aggiungere il contenuto seguente:

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();
    }
}

Problemi? Segnalarli.

Questo codice Java userà database.properties e i file schema.sql creati in precedenza, per connettersi all'istanza del server flessibile Database di Azure per MySQL e creare uno schema che archivierà i dati.

In questo file è possibile notare che i metodi commentati per inserire, leggere, aggiornare ed eliminare i dati verranno codificati nel resto di questo articolo e sarà possibile rimuovere il commento uno dopo l'altro.

Nota

Le credenziali del database sono archiviate nelle proprietà user e password del file database.properties. Queste credenziali vengono usate durante l'esecuzione di DriverManager.getConnection(properties.getProperty("url"), properties);, perché il file delle proprietà viene passato come argomento.

Nota

La riga AbandonedConnectionCleanupThread.uncheckedShutdown(); alla fine è un comando specifico del driver di MySQL per eliminare definitivamente un thread interno quando l'applicazione viene arrestata. Può essere ignorato in modo sicuro.

È ora possibile eseguire questa classe main con lo strumento preferito:

  • Usando l'IDE, dovrebbe essere possibile fare clic con il pulsante destro del mouse sulla classe DemoApplication ed eseguirla.
  • Con Maven è possibile eseguire l'applicazione eseguendo: mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication".

L'applicazione deve connettersi all'istanza del server flessibile Database di Azure per MySQL, creare uno schema del database e quindi chiudere la connessione, come dovrebbe essere visualizzato nei log della console:

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

Creare una classe di dominio

Creare una nuova classe Java Todo accanto alla classe DemoApplication e aggiungere il codice seguente:

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 +
                '}';
    }
}

Questa classe è un modello di dominio mappato alla tabella todo creata durante l'esecuzione dello script schema.sql.

Inserimento di dati in Database di Azure per MySQL

Nel file src/main/java/DemoApplication.java aggiungere il metodo seguente dopo il metodo main per inserire i dati nel database:

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();
}

È ora possibile rimuovere il commento dalle due righe seguenti nel metodo main:

Todo todo = new Todo(1L, "configuration", "congratulations, you have set up JDBC correctly!", true);
insertData(todo, connection);

Se si esegue la classe main, si dovrebbe ottenere l'output seguente:

[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

Lettura dei dati da Database di Azure per MySQL

A questo punto, leggere i dati inseriti in precedenza per verificare il corretto funzionamento del codice.

Nel file src/main/java/DemoApplication.java aggiungere il metodo seguente dopo il metodo insertData per leggere i dati dal database:

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;
}

È ora possibile rimuovere il commento dalla riga seguente nel metodo main:

todo = readData(connection);

Se si esegue la classe main, si dovrebbe ottenere l'output seguente:

[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

Problemi? Segnalarli.

Aggiornamento dei dati nel server flessibile Database di Azure per MySQL

Aggiornare quindi i dati inseriti in precedenza.

Sempre nel file src/main/java/DemoApplication.java aggiungere il metodo seguente dopo il metodo readData per aggiornare i dati all'interno del database:

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);
}

È ora possibile rimuovere il commento dalle due righe seguenti nel metodo main:

todo.setDetails("congratulations, you have updated data!");
updateData(todo, connection);

Se si esegue la classe main, si dovrebbe ottenere l'output seguente:

[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

Eliminazione di dati nel server flessibile Database di Azure per MySQL

Infine, eliminare i dati inseriti in precedenza.

Sempre nel file src/main/java/DemoApplication.java aggiungere il metodo seguente dopo il metodo updateData per eliminare i dati all'interno del database:

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);
}

È ora possibile rimuovere il commento dalla riga seguente nel metodo main:

deleteData(todo, connection);

Se si esegue la classe main, si dovrebbe ottenere l'output seguente:

[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

Pulire le risorse

Complimenti. È stata creata un'applicazione Java che usa JDBC per archiviare e recuperare dati da Database di Azure per MySQL server flessibile.

Per pulire tutte le risorse usate in questo argomento di avvio rapido, eliminare il gruppo di risorse con il comando seguente:

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

Passaggi successivi