Usare Java e JDBC con il database SQL di Azure

Si applica a: 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 database

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

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 il server logico per il database.

Configurare una regola del firewall per il server

Il Database SQL di Azure è protetto per impostazione predefinita in quanto ha 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

Il server 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 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

Leggere i dati

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

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 

Eliminare dati

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