Usare Java e JDBC con il database SQL di Azure

Questo argomento illustra la creazione di un'applicazione di esempio che usa Java e JDBC per archiviare e recuperare le informazioni nel database SQL di Azure.

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

Prerequisiti

Preparare l'ambiente di lavoro

Verranno usate le variabili di ambiente per limitare gli errori di digitazione e per semplificare la personalizzazione della configurazione seguente in base alle esigenze specifiche.

Configurare tali variabili di ambiente usando i comandi seguenti:

AZ_RESOURCE_GROUP=database-workshop
AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
AZ_LOCATION=<YOUR_AZURE_REGION>
AZ_SQL_SERVER_USERNAME=demo
AZ_SQL_SERVER_PASSWORD=<YOUR_AZURE_SQL_PASSWORD>
AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>

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

  • <YOUR_DATABASE_NAME>: il nome del server di database SQL di Azure. 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 l'elenco completo di aree disponibili, immettere az account list-locations.
  • <AZ_SQL_SERVER_PASSWORD>: la password del server di database SQL di Azure. La password deve essere composta da un minimo di otto caratteri La password deve contenere caratteri di tre delle categorie seguenti: lettere maiuscole, lettere minuscole, numeri (0-9) e caratteri non alfanumerici (!, $, #, % e così via).
  • <YOUR_LOCAL_IP_ADDRESS>: l'indirizzo IP del computer locale, da cui verrà eseguita l'applicazione Java. Un modo pratico per trovarlo è puntare il browser all'indirizzo whatismyip.akamai.com.

Creare quindi un gruppo di risorse usando il comando seguente:

az group create \
    --name $AZ_RESOURCE_GROUP \
    --location $AZ_LOCATION \
    | jq

Nota

Viene usata l'utilità jq per visualizzare i dati JSON e renderli più leggibili. Questa utilità viene installata per impostazione predefinita in Azure Cloud Shell. Se non si preferisce usare questa utilità, è possibile rimuovere tranquillamente la parte | jq di tutti i comandi che verranno usati.

Creare un'istanza del database SQL di Azure

Il primo componente che verrà creato è un server di database SQL di Azure gestito.

Nota

Per informazioni più dettagliate sulla creazione di server di database SQL di Azure, vedere Avvio rapido: creare un singolo database SQL di Azure.

In Azure Cloud Shell eseguire il comando seguente:

az sql server create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME \
    --location $AZ_LOCATION \
    --admin-user $AZ_SQL_SERVER_USERNAME \
    --admin-password $AZ_SQL_SERVER_PASSWORD \
    | jq

Questo comando crea un database SQL di Azure.

Configurare una regola del firewall per il server di database SQL di Azure

Le istanze del database SQL di Azure sono protette per impostazione predefinita. Includono un firewall che non consente alcuna connessione in ingresso. Per poter usare il database, è necessario aggiungere una regola del firewall che consenta all'indirizzo IP locale di accedere al server di database.

Poiché all'inizio di questo articolo è stato configurato un indirizzo IP locale, è possibile aprire il firewall del server eseguendo questo comando:

az sql server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME-database-allow-local-ip \
    --server $AZ_DATABASE_NAME \
    --start-ip-address $AZ_LOCAL_IP_ADDRESS \
    --end-ip-address $AZ_LOCAL_IP_ADDRESS \
    | jq

Configurare un database SQL di Azure

Il database SQL di Azure creato in precedenza è vuoto. Non include nessun database che è possibile usare con l'applicazione Java. Creare un nuovo database denominato demo eseguendo questo comando:

az sql db create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name demo \
    --server $AZ_DATABASE_NAME \
    | jq

Creare un nuovo progetto Java

Usando l'IDE preferito, creare un nuovo progetto Java e aggiungere un file pom.xml nella relativa 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>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <version>12.4.2.jre11</version>
        </dependency>
    </dependencies>
</project>

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

  • Java 17
  • Driver SQL Server recente per Java

Preparare un file di configurazione per la connessione al database SQL di Azure

Creare un file src/main/resources/application.properties e aggiungere:

url=jdbc:sqlserver://$AZ_DATABASE_NAME.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
user=demo@$AZ_DATABASE_NAME
password=$AZ_SQL_SERVER_PASSWORD
  • Sostituire le due variabili $AZ_DATABASE_NAME con il valore configurato all'inizio di questo articolo.
  • Sostituire la variabile $AZ_SQL_SERVER_PASSWORD con il valore configurato all'inizio di questo articolo.

Creare un file SQL per generare lo schema del database

Per creare uno schema del database, verrà usato un file src/main/Resources/schema.sql. Creare tale file con il contenuto seguente:

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

Codice dell'applicazione

Stabilire la connessione al database

Aggiungere quindi il codice Java che userà JDBC per archiviare e recuperare i dati dal database SQL di Azure.

Creare un file src/main/java/com/example/demo/DemoApplication.java che contenga:

package com.example.demo;

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

Questo codice Java verranno usati i file application.properties e schema.sql creati in precedenza, per connettersi al database di SQL Server e creare uno schema in cui archiviare i dati.

In questo file è possibile notare che i metodi di inserimento, lettura, aggiornamento ed eliminazione dei dati sono stati commentati. Il codice di tali metodi verranno scritti nella parte restante di questo articolo e sarà possibile rimuovere i commenti uno dopo l'altro.

Nota

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

È 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 package exec:java -Dexec.mainClass="com.example.demo.DemoApplication".

L'applicazione deve connettersi al database SQL di Azure, creare uno schema di database, quindi chiudere la connessione, come si vedrà 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.

Inserire i dati nel database SQL di Azure

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 dal database SQL di Azure

A questo punto verranno letti 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 

Aggiornamento dei dati nel database SQL di Azure

A questo punto, verranno aggiornati 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 database SQL di Azure

A questo punto, verranno eliminati 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 

Conclusione e pulizia delle risorse

Complimenti. È stata creata un'applicazione Java che usa JDBC per archiviare e recuperare i dati dal database SQL di Azure.

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