Skip to content

1. Introduzione

Il PDF di questo documento è disponibile |QUI||.

Gli esempi in questo documento sono disponibili |QUI|.

1.1. Indice

In questo documento proponiamo di studiare diverse configurazioni di implementazione del database. Consideriamo la seguente architettura a livelli:

Il flusso di esecuzione va da sinistra a destra:

  • una delle classi del livello [ui] (Interfaccia utente) viene eseguita per prima. Essa istanzia i livelli [business] e [DAO]. Se il livello [ui] è un'interfaccia utente grafica, attende quindi le azioni dell'utente. Un'azione dell'utente può innescare l'esecuzione di metodi in tutti i livelli dell'architettura fino al database. Il risultato di queste esecuzioni viene restituito all'utente in una forma o nell'altra;

I ruoli dei diversi livelli potrebbero essere i seguenti:

  • Il livello [JDBC] (Java Database Connectivity) è un'interfaccia universale di accesso al database. Presenta sempre la stessa interfaccia al livello [DAO]. Se si cambia DBMS, è sufficiente cambiare il driver JDBC. Il livello [DAO] rimane invariato se ci si è preoccupati di seguire un certo insieme di regole. Tuttavia, è difficile garantire una portabilità al 100% tra i DBMS perché spesso contengono una quantità significativa di SQL proprietario che è difficile ignorare, dato che spesso offre miglioramenti in termini di prestazioni. Non appena si utilizza SQL proprietario, la portabilità tra DBMS non è più possibile. Inoltre, i DBMS hanno spesso politiche diverse per la generazione automatica delle chiavi primarie, così come parole chiave riservate che variano da un sistema all'altro. In questo documento, siamo comunque riusciti a portare l'architettura JDBC studiata su sei diversi DBMS, accettando che per ciascuno di essi sia necessario un progetto di configurazione;
  • il livello [DAO] espone un'interfaccia per l'accesso ai dati dal database specifico in uso (da distinguere dall'interfaccia JDBC, che espone metodi validi per qualsiasi DBMS);
  • il livello [business] implementa le regole di gestione dell'applicazione o le regole di business.
    • I suoi dati di input consistono in dati provenienti dal database tramite il livello [DAO] e/o input dell'utente trasmessi dal livello [UI];
    • Produce dati che può salvare nel database tramite il livello [DAO] e/o restituire al livello [UI] che li ha richiesti, per la visualizzazione da parte dell'utente;
  • Il livello [UI] è il livello che esegue le azioni dell'utente e restituisce i risultati di tali azioni all'utente;

Sopra, il livello [DAO] invia query SQL al livello [JDBC] per l'esecuzione nel DBMS. Negli ultimi anni (dal 2006), questa architettura si è evoluta come segue:

Ora è il livello JPA (Java Persistence API) a inviare le query SQL al livello JDBC e a ricevere i risultati. Il livello [JPA] presenta al livello [DAO] le operazioni di salvataggio, modifica, eliminazione e recupero degli oggetti. Il livello [DAO] non emette più comandi SQL. Questo approccio è più portabile perché le implementazioni JPA gestiscono le differenze tra i DBMS, ma è più lento rispetto alla tecnologia JDBC. Effettueremo dei test delle prestazioni per dimostrarlo. La tecnologia JPA formalizza il lavoro svolto anni fa dal framework Hibernate [http://hibernate.org/].

Esamineremo due livelli [DAO] utilizzando una delle due architetture seguenti:

Richiederemo che i livelli [DAO1] e [DAO2] implementino la stessa interfaccia [IDAO]. In questo modo, il test [JUnitTestsDao] sarà identico per entrambe le configurazioni e ci consentirà di confrontare le prestazioni. Il livello [DAO1] sarà implementato con Spring JDBC e il livello [DAO2] con Spring JPA;

Una volta fatto ciò, esporremo l'interfaccia [IDAO] sul web come segue:

  • In [1], il livello [IDAO] è esposto sul web tramite un livello web [2] implementato da Spring MVC. È infatti l'interfaccia [IDAO] ad essere esposta, e realizzeremo due versioni del servizio web a seconda che tale interfaccia sia implementata utilizzando un'architettura [DAO-JDBC] o [DAO-JPA-JDBC];
  • In [B], un client remoto utilizza gli URL esposti dal servizio web, che forniscono l'accesso ai metodi del livello [IDAO-server]. Ci assicureremo che il livello [DAO-Client] [3] implementi l'interfaccia [IDAO-server] [1]. Questo ci consentirà di utilizzare lo stesso test [JUnitTestsDao] che è già stato utilizzato due volte [4];
  • In [3], il livello [DAO-Client] sarà implementato utilizzando Spring RestTemplate;

Una volta fatto ciò, proteggeremo l'accesso al servizio web:

  • in [5], la richiesta HTTP del client passa attraverso un livello di autenticazione implementato con Spring Security;

Una volta fatto ciò, evolveremo l'architettura precedente nella seguente:

  • In [3], l'applicazione client è essa stessa un'applicazione web. Presenterà un modulo [5] che consentirà agli utenti di interrogare gli URL del servizio web sicuro. L'accesso HTTP al servizio web sicuro sarà gestito tramite un livello [DAO-client-js] implementato in JavaScript. Questa architettura utilizza le cosiddette richieste cross-domain:
    • il servizio web [2] fornisce URL del tipo [http://machine1:port1/];
    • l'applicazione web client [3] viene scaricata da un URL [http://machine2:port2/]. Se [http://machine2:port2/] non è identico a [http://machine1:port1/] (stessa macchina, stessa porta), il browser client bloccherà le chiamate HTTP provenienti dal livello [DAO-client-js]. Per risolvere questo problema, il servizio web deve consentire le richieste cross-domain. Vedremo come;

I progetti presentati sono stati testati con i seguenti sei DBMS:

  • MySQL 5 Community Edition;
  • SQL Server 2014 Express;
  • PostgreSQL 9.4;
  • Oracle Express 11g Release 2;
  • IBM DB2 Express-C 10.5;
  • Firebird 2.5.4;

Per ciascuno di questi DBMS, abbiamo sviluppato quattro diversi livelli [DAO]:

  • un livello implementato con Spring JDBC;
  • un livello implementato con Spring JPA e il provider JPA Hibernate;
  • un livello implementato con Spring JPA e il provider JPA EclipseLink;
  • un livello implementato con Spring JPA e il provider JPA OpenJPA;

Pertanto, qui viene presentata una serie di ventiquattro diverse configurazioni. Abbiamo compiuto uno sforzo significativo per fattorizzare il codice:

  • la maggior parte del codice è scritta una sola volta. Si basa su due progetti di configurazione Maven:
    • uno configura il livello JDBC;
    • l'altro configura il livello JPA;

Il progetto di configurazione Maven per il livello JDBC [1] di un DBMS specifico si articola in due fasi:

  • importazione dell'archivio del driver JDBC;
  • definizione delle credenziali di accesso al database in uso e delle varie istruzioni SQL che il livello [DAO1] invierà al driver JDBC. Sebbene l'SQL sia standardizzato, abbiamo riscontrato problemi di portabilità dovuti principalmente alla presenza nelle query di nomi di tabelle/colonne che si sono rivelati parole chiave proibite in alcuni DBMS (la tabella ROLES per DB2, la colonna PASSWORD per Firebird). Inoltre, sebbene un nome di colonna sia normalmente insensibile alle maiuscole/minuscole, abbiamo riscontrato un problema con PostgreSQL riguardo alla colonna ID della chiave primaria nelle tabelle. Richiedeva che fosse denominata "id" in minuscolo. Questi sono esempi tipici di problemi di portabilità inattesi;

Anche i tre progetti Maven per la configurazione del livello JPA [2] di un DBMS specifico consistono in due passaggi:

  • importazione dell'archivio di implementazione JPA;
  • configurare l'implementazione JPA utilizzata per lo specifico DBMS collegato. Infatti, è il livello JPA che invia i comandi SQL al livello JDBC. Per essere efficace, deve conoscere il DBMS al fine di inviargli comandi SQL che esso riconoscerà. Questi comandi possono utilizzare l'SQL proprietario di quel DBMS così come le sue caratteristiche specifiche (tipi di dati, sequenze, trigger, procedure, generazione automatica di chiavi primarie, ecc.);

Ciò si traduce in ventiquattro progetti di configurazione Maven (4 configurazioni × 6 DBMS) su cui si baseranno tutti gli altri progetti di gestione del database. Nei diagrammi sopra riportati, poiché i livelli [DAO1] e [DAO2] forniscono la stessa interfaccia, le 24 configurazioni delle due architetture sopra indicate saranno testate utilizzando un'unica classe di test [JUnitTestsDao]. Una volta verificate queste architetture, non ci sono ulteriori difficoltà:

  • il progetto Maven per la pubblicazione del database sul web si basa su queste due architetture. Ci sono quindi anche qui 24 possibili configurazioni;
  • il progetto Maven per la protezione dell'accesso al servizio web si basa sul progetto precedente e presenta anch'esso 24 possibili configurazioni;
  • Infine, il progetto Maven che consente le richieste interdominio al servizio web protetto si basa sul progetto precedente e offre anch'esso 24 possibili configurazioni;

Lo studio è condotto utilizzando il DBMS MySQL5 e l'implementazione JPA di Hibernate. Successivamente, portiamo il codice alle implementazioni JPA di Eclipselink e OpenJPA. Infine, lo portiamo su altri database (PostgreSQL, Oracle, SQL Server, DB2, Firebird).

Questo corso è rivolto ai principianti. La maggior parte dei concetti utilizzati viene spiegata. Non è richiesta alcuna conoscenza preliminare di programmazione di database o di programmazione web. Tuttavia, è necessaria una solida comprensione del linguaggio SQL, poiché le query SQL utilizzate non vengono spiegate.

Per comprendere gli esempi, è necessaria una conoscenza di base del linguaggio Java, che si può acquisire in qualsiasi corso introduttivo sul linguaggio. Saranno sufficienti i primi due capitoli del documento [Introduzione al linguaggio Java]. Si tratta di un documento datato (1998, rivisto nel 2002), ma i fondamenti ci sono. Per un corso completo, si può leggere l'ampio libro di Jean-Marie Doudoux [http://www.jmdoudoux.fr/java].

Questo documento non è affatto esaustivo. Ha il solo scopo di fornire una metodologia e un codice che possano essere riutilizzati in contesti simili. Il documento è stato scritto in modo da poter essere letto senza avere un computer a portata di mano. Pertanto, sono incluse molte schermate.

Sebbene non copra tutte le funzionalità del linguaggio Java né tutte le sue aree di applicazione, questo documento può essere utilizzato come risorsa di apprendimento per il linguaggio. Seguendo questo documento, anche se non nella sua interezza, un lettore principiante raggiungerà un livello "Java avanzato" sia nell'uso del linguaggio che del framework Spring. Potrà quindi continuare la propria formazione su Java con i seguenti libri:

  • [Spring MVC and Thymeleaf by Example] [https://stahe.github.io/it-springmvc-thymeleaf-janv-2015/], che continua l'esplorazione dell'ecosistema Spring introducendo il suo ramo della "programmazione web MVC";
  • [AngularJS / Spring MVC Tutorial] [https://stahe.github.io/it-spring-angular1.x-juillet-2014/], che presenta un'architettura web client/server, in cui il client è implementato utilizzando il framework [AngularJS] e il server utilizzando [Spring MVC];
  • [Introduzione a Java EE], che si allontana dall'ecosistema Spring per passare a un'architettura web basata su JSF (Java Server Faces) ed EJB (Enterprise JavaBeans);
  • [Introduzione alla programmazione su tablet Android] [https://stahe.github.io/it-android-aout-2016/] che descrive un'architettura client/server, in cui il client è un tablet Android e il server è un servizio web implementato da Spring MVC;

1.2. Fonti

Questo documento ha due fonti principali:

  • [ ref1]: [Spring MVC e Thymeleaf con esempi] all'URL [https://stahe.github.io/it-springmvc-thymeleaf-janv-2015/]. Questo documento riprende il lavoro svolto e presentato in [ref1] utilizzando un database diverso. In parole povere, lo rimuove dal contesto della programmazione web con Spring MVC. Ho deciso di creare un documento separato perché ho ritenuto che il codice e la metodologia utilizzati in [ref1] per esporre un database sul web fossero riutilizzabili;
  • [ ref2]: [Java Persistence in Practice] all'URL [https://stahe.github.io/it-jpa-juin-2007/];

Per saperne di più su Spring, è possibile consultare i seguenti riferimenti:

I lettori con conoscenze SQL insufficienti possono apprendere le nozioni di base dal libro [Introduzione a SQL con il DBMS Firebird] all'indirizzo [https://stahe.github.io/it-sql-firebird-janv-2006/].

1.3. Strumenti utilizzati

Gli esempi seguenti sono stati testati nel seguente ambiente:

Nota relativa a JDK 1.8: un metodo nel caso di studio utilizza un metodo del pacchetto [java.lang] in Java 8.

La maggior parte degli esempi sono progetti Maven che possono essere aperti in Eclipse, IntelliJ IDEA o NetBeans. Di seguito, le schermate provengono dall'IDE Spring Tool Suite, una variante di Eclipse.

1.4. Gli esempi

Gli esempi sono disponibili |QUI| come file ZIP scaricabile.

  • In [1], le cartelle degli esempi;
  • in [2], la cartella [spring-core] contiene i progetti di apprendimento Spring;
  • in [3], la cartella [spring-database-config] contiene i progetti di configurazione JDBC e JPA per i sei database;
  • in [4], la configurazione del DBMS Oracle. Contiene tre cartelle:
    • [databases] contiene gli script SQL per la generazione dei due database utilizzati nel documento;
    • [jdbc-driver] contiene il driver JDBC di Oracle e uno script per installarlo nel repository Maven locale;
    • [eclipse] contiene [5] i quattro progetti di configurazione Oracle:
      • [oracle-config-jdbc] configura il livello JDBC per l'accesso al DBMS;
      • [oracle-config-jpa-hibernate] configura il livello JPA per l'accesso al DBMS utilizzando il provider JPA Hibernate;
      • [oracle-config-jpa-eclipselink] configura il livello JPA per l'accesso al database utilizzando il provider JPA Eclipselink;
      • [oracle-config-jpa-openjpa] configura il livello JPA per l'accesso al database utilizzando il provider JPA OpenJPA;
  • in [6], la cartella [eclipse config / launch configurations] contiene le configurazioni di avvio che il lettore può importare in Eclipse e poi adattare al proprio ambiente;
  • in [7], la cartella [spring-database-generic] contiene tutto il codice di accesso al DB comune ai sei DBMS e ai tre provider JPA;
  • In [8], [spring-jdbc] contiene quattro progetti che illustrano l'API JDBC e Spring JDBC;
  • In [9], [spring-jpa / spring-jpa-generic] è il progetto che utilizza un livello JPA per accedere a un database. I progetti [generic-create-db*] sono progetti JPA utilizzati per creare i database utilizzati dal livello JPA;
  • In [10], la cartella [spring-webjson] contiene i progetti che espongono il database sul web;

    • [spring-webjson-server-jdbc-generic] è il servizio web che espone il database accessibile tramite Spring JDBC;
    • [spring-webjson-server-jpa-generic] è il servizio web che espone il database accessibile tramite Spring JPA;
    • [spring-webjson-client-generic] è il client unico che consente l'accesso ai due servizi web precedenti;
  • in [11], la cartella [spring-security] contiene i progetti che espongono il database sul web con accesso sicuro;

    • [spring-security-server-jdbc-generic] è il servizio web protetto che espone il database accessibile tramite Spring JDBC;
    • [spring-security-server-jpa-generic] è il servizio web protetto che espone il database accessibile tramite Spring JPA;
    • [spring-security-client-generic] è l'unico client che consente l'accesso ai due precedenti servizi web protetti;
  • in [12], la cartella [spring-cors] contiene i progetti che espongono il database sul web con accesso sicuro consentendo l'accesso cross-domain, come quello proveniente dal codice JavaScript di un browser;

    • [spring-cors-server-jdbc-generic] è il servizio web sicuro che consente l'accesso cross-domain ed espone il database accessibile tramite Spring JDBC;
    • [spring-cors-server-jpa-generic] è il servizio web sicuro che consente l'accesso cross-domain ed espone il database accessibile tramite Spring JPA;
    • [spring-cors-client-generic] è un'applicazione web che interroga i due servizi web precedenti;