Skip to content

1. Inleiding

De PDF van dit document is beschikbaar |HIER||.

De voorbeelden in dit document zijn beschikbaar |HIER|.

1.1. Contenu

In dit document willen we verschillende configuraties voor het gebruik van een database bestuderen. Laten we de volgende gelaagde architectuur eens bekijken:

De uitvoeringsstroom verloopt van links naar rechts:

  • een van de klassen van de laag [ui] (Use Interface) wordt als eerste uitgevoerd. Deze klasse instantiëert de lagen [metier] en [dao]. Als de laag [ui] een grafische interface is, wacht deze vervolgens op acties van de gebruiker. Een actie van de gebruiker kan leiden tot de uitvoering van methoden in alle lagen van de architectuur, tot aan de database toe. Het resultaat van deze uitvoeringen wordt op de een of andere manier aan de gebruiker weergegeven;

De rol van de verschillende lagen zou als volgt kunnen zijn:

  • de laag [JDBC] (Java DataBase Connectivity) is een universele interface voor toegang tot databases. Deze biedt altijd dezelfde interface aan de laag [DAO]. Als men van SGBD verandert, volstaat het om de driver JDBC te wijzigen. De laag [DAO] verandert niet, mits men zich aan een aantal regels heeft gehouden. Het is echter moeilijk om 100% overdraagbaarheid tussen SGBD te garanderen, omdat deze vaak een aanzienlijk aandeel aan propriëtaire SQL bevatten dat moeilijk te negeren is, aangezien dit vaak prestatieverbeteringen oplevert. Zodra er eigen SQL wordt gebruikt, is portabiliteit naar SGBD niet meer mogelijk. Bovendien hanteren de SGBD-versies vaak verschillende beleidsregels voor het automatisch genereren van primaire sleutels, en zijn de gereserveerde woorden hier en daar niet hetzelfde. In dit document is het ons toch gelukt om de bestudeerde JDBC-architectuur naar zes verschillende SGBD-versies te porten, waarbij we hebben geaccepteerd dat er voor elk daarvan een configuratieproject nodig is;
  • de [DAO]-laag biedt een interface voor toegang tot de gegevens van de specifieke gebruikte database (te onderscheiden van de JDBC-interface, die methoden biedt die voor elke SGBD gelden);
  • de laag [métier] implementeert de beheerregels of bedrijfsregels van de applicatie.
    • de invoergegevens bestaan uit gegevens afkomstig uit de database via de laag [dao] en/of gegevens van de gebruiker die door de laag [ui] worden doorgegeven;
    • de laag genereert gegevens die via de laag [dao] in de database kunnen worden opgeslagen en/of kunnen worden teruggestuurd naar de laag [ui] die de aanvraag heeft gedaan, zodat deze aan de gebruiker kunnen worden getoond;
  • de laag [ui] is de laag die de acties van de gebruiker uitvoert en de resultaten daarvan aan hem terugstuurt;

Hierboven stuurt de laag [DAO] verzoeken SQL naar de laag [JDBC] voor uitvoering in de laag SGBD. Sinds enkele jaren (2006) kan deze architectuur als volgt evolueren:

Het is nu de laag JPA (Java Persistence API) die SQL-verzoeken naar de laag JDBC verstuurt en de resultaten daarvan ontvangt. De laag [JPA] biedt de laag [DAO] bewerkingen aan voor het opslaan, wijzigen, verwijderen en ophalen van objecten. De laag [DAO] verstuurt geen SQL-opdrachten meer. Deze aanpak is beter overdraagbaar omdat de JPA-implementaties de verschillen met SGBD afhandelen, maar hij is trager dan de JDBC-technologie. We zullen prestatietests uitvoeren om dit aan te tonen. De JPA-technologie formaliseert het werk dat jaren geleden door het Hibernate-framework [http://hibernate.org/] is verricht.

We zullen twee lagen [DAO] bestuderen met een van de volgende twee architecturen:

We zullen de lagen [DAO1] en [DAO2] verplichten om dezelfde interface [IDAO] te implementeren. Daardoor zal de test [JUnitTestsDao] voor beide configuraties hetzelfde zijn, waardoor we de prestaties kunnen vergelijken. De laag [DAO1] wordt geïmplementeerd met Spring JDBC en de laag [DAO2] met Spring JPA;

Zodra dit is gebeurd, zullen we de interface [IDAO] op de volgende manier op het web beschikbaar stellen:

  • in [1] wordt de laag [IDAO] op het web beschikbaar gesteld via een weblaag [2] die is geïmplementeerd door Spring MVC. Het is inderdaad de interface [IDAO] die beschikbaar wordt gesteld en we zullen twee versies van de webservice bouwen, afhankelijk van of deze interface wordt geïmplementeerd met een [DAO-JDBC]- of een [DAO-JPA-JDBC]-architectuur;
  • In [B] maakt een externe client gebruik van de URL die door de webservice worden aangeboden en die toegang geven tot de methoden van de [IDAO-serveur]-laag. We zorgen ervoor dat de laag [DAO-Client] [3] de interface [IDAO-serveur] [1] implementeert. Hierdoor kunnen we dezelfde test [JUnitTestsDao] gebruiken die al twee keer is gebruikt ([4]);
  • in [3] zal de laag [DAO-client] worden geïmplementeerd met Spring RestTemplate;

Zodra dit is gebeurd, beveiligen we de toegang tot de webservice:

  • in [5] doorloopt het verzoek HTTP van de client een authenticatielaag die is geïmplementeerd met Spring Security;

Zodra dit is gebeurd, zullen we de vorige architectuur uitbreiden naar de volgende:

  • in [3] is de clienttoepassing zelf een webtoepassing. Deze toont een formulier [5] waarmee de URL van de beveiligde webservice kunnen worden opgevraagd. De HTTP-toegangen tot de beveiligde webservice vinden plaats via een in JavaScript geïmplementeerde [DAO-client-js]-laag. Deze architectuur maakt gebruik van zogenaamde cross-domain-verzoeken:
    • de webservice [2] presenteert URL in de vorm [http://machine1:port1/];
    • de client-webapplicatie [3] wordt gedownload vanaf een URL [http://machine2:port2/]. Als [http://machine2:port2/] niet identiek is aan [http://machine1:port1/] (dezelfde machine, dezelfde poort), dan blokkeert de clientbrowser de HTTP-aanroepen vanuit de [DAO-client-js]-laag. Om dit probleem op te lossen, moet de webservice verzoeken tussen domeinen toestaan. We zullen zien hoe;

De gepresenteerde projecten zijn getest met de volgende zes SGBD:

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

Voor elk van deze SGBD zijn vier verschillende [DAO]-lagen ontwikkeld:

  • een laag geïmplementeerd met Spring JDBC;
  • een laag geïmplementeerd met Spring JPA en de Hibernate-provider JPA;
  • een laag geïmplementeerd met Spring JPA en de provider JPA EclipseLink;
  • een laag geïmplementeerd met Spring JPA en de provider JPA OpenJPA;

Hier wordt dus een reeks van vierentwintig verschillende configuraties gepresenteerd. Er is veel aandacht besteed aan het opschalen van de code:

  • het grootste deel van de code is slechts één keer geschreven. Het is gebaseerd op twee Maven-configuratieprojecten:
    • het ene configureert de laag JDBC;
    • de andere configureert de laag JPA;

Het Maven-configuratieproject voor de laag JDBC [1] van een specifieke SGBD bestaat uit twee stappen:

  • het importeren van het stuurprogramma-archief JDBC;
  • het definiëren van de toegangsgegevens voor de gebruikte database en de verschillende SQL-opdrachten die de [DAO1]-laag naar de JDBC-driver zal verzenden. Hoewel SQL gestandaardiseerd is, zijn er portabiliteitsproblemen opgetreden, voornamelijk vanwege de aanwezigheid in de query's van tabel- en kolomnamen die in bepaalde SGBD-systemen verboden sleutelwoorden bleken te zijn (tabel ROLES voor DB2, kolom PASSWORD voor Firebird). Bovendien, hoewel een kolomnaam normaal gesproken hoofdletter- en kleine lettergevoelig is, is er een probleem opgetreden met PostgreSQL met betrekking tot de kolom ID van de primaire sleutel van de tabellen. Het systeem wilde dat deze kolom id in kleine letters heette. Dit zijn typische voorbeelden van onverwachte portabiliteitsproblemen;

De drie Maven-configuratieprojecten van de laag JPA [2] van een specifieke SGBD bestaan eveneens uit twee punten:

  • het importeren van het archief van de implementatie JPA;
  • de implementatie JPA configureren die wordt gebruikt voor de specifieke, aangesloten SGBD. Het is namelijk de laag JPA die de opdrachten SQL naar de laag JDBC verzendt. Om effectief te zijn, moet deze laag de SGBD kennen om de SQL-opdrachten naar deze laag te kunnen sturen, die deze zal herkennen. Deze opdrachten kunnen gebruikmaken van de SQL, de eigenaar van deze SGBD, evenals van de specifieke kenmerken daarvan (datatypes, sequenties, triggers, procedures, automatische generatie van primaire sleutels, ...);

Zo zijn er vierentwintig Maven-configuratieprojecten (4 configuraties x 6 SGBD) waarop alle andere projecten voor het gebruik van de database zullen steunen. Aangezien de lagen [DAO1] en [DAO2] in de bovenstaande schema’s dezelfde interface bieden, zullen de 24 configuraties van de twee bovengenoemde architecturen worden getest met één enkele testklasse [JUnitTestsDao]. Zodra deze architecturen zijn geverifieerd, zijn er geen problemen meer:

  • het Maven-project voor het publiceren van de database op het web is gebaseerd op deze twee architecturen. Er zijn dus ook hier 24 mogelijke configuraties;
  • het Maven-project voor het beveiligen van de toegang tot de webservice bouwt voort op het vorige project en kent eveneens 24 mogelijke configuraties;
  • ten slotte is het Maven-project dat verzoeken tussen domeinen naar de beveiligde webservice mogelijk maakt, gebaseerd op het vorige project en kent eveneens 24 mogelijke configuraties;

Het onderzoek is uitgevoerd met SGBD, MySQL5 en de Hibernate-implementatie JPA. Vervolgens wordt de port naar de implementaties JPA (Eclipselink) en OpenJPA uitgevoerd. Vervolgens wordt de port naar de andere databases uitgevoerd (PostgresQL, Oracle, SQL Server, DB2, Firebird).

Deze cursus is bedoeld voor beginners. Het merendeel van de gebruikte concepten wordt uitgelegd. Kennis van databaseprogrammering of webprogrammering is niet vereist. Wel is een gedegen kennis van de taal SQL nodig, aangezien de gebruikte SQL-query’s niet worden uitgelegd.

Om de voorbeelden te begrijpen, is basiskennis van de programmeertaal Java vereist, die in elke inleidende cursus over deze taal wordt behandeld. De eerste twee hoofdstukken van het document [Introduction au langage Java] volstaan. Het is een oud document (uit 1998, herzien in 2002), maar de basis is aanwezig. Voor een volledige cursus kan men het omvangrijke boek van Jean-Marie Doudoux, [http://www.jmdoudoux.fr/java], raadplegen.

Dit document is geenszins volledig. Het is alleen bedoeld om een methodologie en codevoorbeelden te bieden die in vergelijkbare contexten kunnen worden hergebruikt. Het document is zo geschreven dat het kan worden gelezen zonder dat men een computer bij de hand heeft. Daarom worden er veel schermafbeeldingen getoond.

Hoewel dit document niet alle mogelijkheden van de Java-taal noch alle toepassingsgebieden ervan behandelt, kan het worden gebruikt als leermateriaal voor de taal. Als de beginnende lezer dit document niet in zijn geheel volgt, zal hij toch een „gevorderd Java-niveau“ bereiken, zowel wat het gebruik van de taal als dat van het Spring-framework betreft. Hij kan zijn Java-opleiding dan voortzetten met de volgende werken:

1.2. Sources

Dit document heeft twee belangrijke bronnen:

Om meer te weten te komen over Spring, kun je de volgende bronnen raadplegen:

  • het referentiedocument van het Spring-framework [http://docs.spring.io/spring/docs/current/spring-framework-reference/pdf/spring-framework-reference.pdf];
  • talrijke Spring-tutorials zijn te vinden op de URL [http://spring.io/guides];
  • de website van [developpez.com] gewijd aan Spring [http://spring.developpez.com/];
  • de tutorial [http://www.tutorialspoint.com/spring/spring_tutorial.pdf];

Lezers met onvoldoende kennis van SQL kunnen de basisbeginselen leren met het boek [Introduction au langage SQL avec le SGBD Firebird] op URL [http://tahe.developpez.com/divers/sql-firebird/].

1.3. De gebruikte tools

De volgende voorbeelden zijn getest in de volgende omgeving:

  • Windows 8.1 Pro 64-bits;
  • JDK 1.8 (paragraaf 23.1);
  • IDE Spring Tool Suite 3.6.3 (paragraaf 1);
  • Chrome-browser (andere browsers zijn niet gebruikt);
  • Chrome-extensie [Advanced Rest Client] (paragraaf 1);
  • SGBD MySQL 5.6 Community Edition (paragraaf 23.4);
  • SGBD SQL Server 2014 Express (paragraaf 23.9);
  • SGBD PostgreSQL 9.4 (paragraaf 23.7);
  • SGBD Oracle Express 11g release 2 (paragraaf 23.6);
  • SGBD IBM DB2 Express-C 10.5 (paragraaf 23.8);
  • SGBD Firebird 2.5.4 (paragraaf 23.10);
  • de EMS Manager-clients van zijn zes SGBD (paragraaf 23.5);

Let op JDK 1.8. In een van de casestudy's wordt een methode uit het [java.lang]-pakket van Java 8 gebruikt.

De meeste voorbeelden zijn Maven-projecten die zowel in IDE Eclipse, IntellijIDEA als in NetBeans kunnen worden geopend. De schermafbeeldingen hieronder zijn afkomstig uit de IDE Spring Tool Suite, een variant van Eclipse.

1.4. De voorbeelden

De voorbeelden zijn beschikbaar op URL [http://tahe.developpez.com/java/spring-database] in de vorm van een downloadbaar bestand zip.

  • in [1], de mappen met voorbeelden;
  • in [2] bevat de map [spring-core] de Spring-leerprojecten;
  • in [3] bevat de map [spring-database-config] de configuratieprojecten JDBC en JPA van de zes databases;
  • in [4], de configuratie van de Oracle-database SGBD. Daarin bevinden zich drie mappen:
    • [databases] bevat de scripts SQL voor het genereren van de twee databases die door het document worden gebruikt;
    • [jdbc-driver] bevat de Oracle-driver JDBC en een script om deze in de lokale Maven-repository te installeren;
    • [eclipse] bevat [5] de vier Oracle-configuratieprojecten:
      • [oracle-config-jdbc] configureert de toegangslaag JDBC voor SGBD;
      • [oracle-config-jpa-hibernate] configureert de toegangslaag JPA voor SGBD met de Hibernate-provider JPA;
      • [oracle-config-jpa-eclipselink] configureert de toegangslaag JPA voor SGBD met de provider JPA Eclipselink;
      • [oracle-config-jpa-openjpa] configureert de toegangslaag JPA voor SGBD met de provider JPA OpenJPA;
  • in [6] bevat het bestand [eclipse config / launch configurations] de uitvoeringsconfiguraties die de gebruiker in Eclipse kan importeren om ze vervolgens aan te passen aan zijn eigen omgeving;
  • in [7], de map [spring-database-generic] bevat alle toegangscode voor SGBD, die gemeenschappelijk is voor de zes SGBD-bestanden en de drie leveranciers JPA;
  • in [8] bevat [spring-jdbc] vier projecten die API, JDBC en Spring JDBC omvatten;
  • in [9] is [spring-jpa / spring-jpa-generic] het project dat gebruikmaakt van een laag JPA om toegang te krijgen tot een database. De projecten [generic-create-db*] zijn JPA-projecten waarmee de databases kunnen worden aangemaakt die door de laag JPA worden gebruikt;
  • in [10] bevat de map [spring-webjson] de projecten die de database op het web beschikbaar stellen;

    • [spring-webjson-server-jdbc-generic] is de webservice die de database beschikbaar stelt die via Spring JDBC wordt benaderd;
    • [spring-webjson-server-jpa-generic] is de webservice die de database beschikbaar stelt die via Spring JPA wordt benaderd;
    • [spring-webjson-client-generic] is de enige client waarmee toegang kan worden verkregen tot de twee voorgaande webservices;
  • in [11] bevat de map [spring-security] de projecten die de database via het web beschikbaar stellen met beveiligde toegang;

    • [spring-security-server-jdbc-generic] is de beveiligde webservice die de database beschikbaar stelt die via Spring JDBC wordt benaderd;
    • [spring-security-server-jpa-generic] is de beveiligde webservice die de database beschikbaar stelt die via Spring JPA wordt benaderd;
    • [spring-security-client-generic] is de enige client waarmee toegang kan worden verkregen tot de twee voorgaande beveiligde webservices;
  • in [12] bevat de map [spring-cors] de projecten die de database via het web beschikbaar stellen met beveiligde toegang, waardoor domeinoverschrijdende toegang mogelijk is, zoals vanuit de JavaScript-code van een browser;

    • [spring-cors-server-jdbc-generic] is de beveiligde webservice die domeinoverschrijdende toegang mogelijk maakt en die de database beschikbaar stelt die via Spring JDBC wordt benaderd;
    • [spring-cors-server-jpa-generic] is de beveiligde webservice die domeinoverschrijdende toegang mogelijk maakt en die de database beschikbaar stelt die via Spring JPA wordt benaderd;
    • [spring-cors-client-generic] is een webapplicatie waarmee de twee voorgaande webservices kunnen worden opgevraagd;