9. Generazione dei database a partire dalle entità JPA
È possibile creare le tabelle di un database a partire dalle entità JPA. È proprio ciò che mostreremo ora. L’obiettivo è verificare che il database generato a partire dalle entità JPA sia effettivamente quello desiderato.
9.1. Configurazione dell’ambiente di lavoro
Lavoreremo innanzitutto con un’implementazione JPA EclipseLink [1].
![]() |
Quindi eliminiamo le tabelle del database MySQL e [dbproduitscategories] utilizzando il client [MyManager] (cfr. paragrafo 23.5). Iniziamo eliminando le tabelle che contengono le chiavi esterne [1-3]:
![]() |
Quindi ricominciamo con le tre tabelle rimanenti [4-6]:
![]() |
Procediamo allo stesso modo con la tabella [dbproduits] utilizzata dai progetti [spring-jdbc-01 à 03]:
![]() | ![]() |
Inoltre, è necessario importare i due progetti di generazione delle due basi di dati:
![]() |
- in [1], si importa il progetto [generic-create-dbproduits] che si trova in [<exemples>/spring-database-generic/spring-jpa] [2];
![]() |
- in [4], si importa il progetto [generic-create-dbproduitscategories] che si trova in [<exemples>/spring-database-generic/spring-jpa] [5];
Nota: premere Alt-F5 e rigenerare tutti i progetti Maven;
9.2. Generazione del database [dbproduitscategories]
![]() |
9.2.1. Configurazione Maven
Il file [pom.xml] del progetto è il seguente:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-create-dbproduitscategories</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>generic-create-dbproduitscategories</name>
<description>création de la bases de données [dbproduitscategories] à l'aide des annotations JPA</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- spring-jpa-generic -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>spring-jpa-generic</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Weaver Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>spring.data.console.Main</start-class>
<java.version>1.7</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- righe 22-26: la dipendenza dal progetto [spring-jpa-generic] analizzato nel paragrafo 6.4;
- righe 28-32: la dipendenza da un weaver che verrà utilizzato per arricchire le entità JPA delle implementazioni EclipseLink e OpenJpa. La sua dipendenza non è necessaria nel file [pom.xml], ma il suo JAR sarà l'agente Java utilizzato. Inserire la dipendenza nel file [pom.xml] ci assicura che il JAR sia effettivamente disponibile;
In definitiva, le dipendenze sono le seguenti:
![]() |
9.2.2. Configurazione Spring
![]() |
La classe [AppConfig] configura il progetto Spring:
package console;
import generic.jpa.config.ConfigJpa;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@Configuration
@Import({ ConfigJpa.class })
@EnableJpaRepositories(basePackages = { "console" })
public class AppConfig {
}
- riga 10: la classe recupera i bean della classe [ConfigJpa]. Si ricorda che questa classe opera con le entità JPA del database [dbproduitscategories] (cfr. paragrafo 6.3);
- riga 11: si dichiara che il pacchetto [console] deve essere analizzato per individuare le istanze [CrudRepository];
Nella classe [ConfigJpa] si trova il seguente bean (varia a seconda dell'implementazione JPA utilizzata):
// il provider JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
// Nota: le entità JPA e la configurazione di EclipseLink si trovano nel file META-INF/persistence.xml
EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter = new EclipseLinkJpaVendorAdapter();
eclipseLinkJpaVendorAdapter.setShowSql(false);
eclipseLinkJpaVendorAdapter.setDatabase(Database.MYSQL);
eclipseLinkJpaVendorAdapter.setGenerateDdl(true);
return eclipseLinkJpaVendorAdapter;
}
In questo caso è importante la riga 8. È presente in tutte le implementazioni JPA utilizzate. Indica che, se le tabelle associate alle entità JPA non esistono, devono essere create. Ci baseremo su questa proprietà per generare le tabelle.
9.2.3. I repository
![]() |
L’interfaccia [ProduitsRepository] è la seguente:
package console;
import generic.jpa.entities.dbproduitscategories.Produit;
import org.springframework.data.repository.CrudRepository;
public interface ProduitsRepository extends CrudRepository<Produit, Long> {
}
È la sua istanziazione che provocherà l’istanziazione del livello JPA. Infatti, alla riga 7, l'interfaccia fa riferimento all'entità JPA [Produit], il che costringerà l'istanziazione del livello JPA. Si sarebbe potuto inserire qualsiasi interfaccia [CrudRepository] che facesse riferimento a una delle entità JPA. Si nota infatti che, sebbene [repository] faccia riferimento solo all’entità JPA [Produit], vengono generate tutte le tabelle di tutte le entità JPA.
9.2.4. La classe eseguibile
![]() |
La classe [CreateDatabase] è la seguente:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class CreateDataBase {
public static void main(String[] args) {
// È sufficiente istanziare il contesto Spring per creare le tabelle del database [dbproduitscategories]
// è necessario anche almeno un Spring Data Repository, altrimenti non succede nulla
System.out.println("Travail en cours...");
new AnnotationConfigApplicationContext(AppConfig.class).close();
System.out.println("Travail terminé...");
}
}
- riga 11: si istanzia il contesto Spring per chiuderlo immediatamente. In questo contesto è presente il bean [ProduitsRepository] che fa riferimento alle entità JPA e [Produit]. Ciò è sufficiente per istanziare il livello JPA e quindi generare le tabelle del database [dbproduitscategories].
9.2.5. Generazione delle tabelle con EclipseLink
Ci troviamo nella seguente configurazione:
![]() |
- il livello [JDBC] è configurato per il database [dbproduitscategories] di MySQL;
- il livello [JPA] è implementato con EclipseLink;
- il database [dbproduitscategories] non contiene tabelle;
Nota: premere Alt-F5 e rigenerare tutti i progetti Maven;
Si utilizza la seguente configurazione di esecuzione:
![]() |
- in [1-2], questa configurazione di esecuzione richiede un agente Java affinché il test abbia esito positivo. A seconda dei casi, EclipseLink non sempre necessita di questo agent, ma in questo caso l'esecuzione fallisce se non è presente. Questo agent non è un agent EclipseLink, bensì un agent Spring. È fornito dalla dipendenza:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<scope>runtime</scope>
</dependency>
registrata nel file [pom.xml] del progetto. L'agente si trova in [<m2-repo>/org/springframework/spring-instrument/4.1.6.RELEASE/spring-instrument-4.1.6.RELEASE.jar], dove <m2-repo> è il repository locale di Maven;
L'esecuzione produce il seguente risultato:
![]() |
Nel file [3] si vede che le tabelle sono state generate. Ora verifichiamo il file DDL (Domain Definition Language) del database:
![]() | ![]() |
![]() |
Lo script SQL per la generazione delle tabelle può essere salvato anche in un file [1].
![]() | ![]() ![]() |
Lo script SQL generato è il seguente:
SET FOREIGN_KEY_CHECKS=0;
USE `dbproduitscategories`;
CREATE TABLE `categories` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `NOM` (`NOM`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `produits` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`DESCRIPTION` VARCHAR(100) COLLATE utf8_general_ci DEFAULT NULL,
`CATEGORIE_ID` BIGINT(20) NOT NULL,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRIX` DOUBLE NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
`CATEGORIE` INTEGER(11) NOT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `NOM` (`NOM`) USING BTREE,
KEY `FK_PRODUITS_CATEGORIE_ID` (`CATEGORIE_ID`) USING BTREE,
CONSTRAINT `FK_PRODUITS_CATEGORIE_ID` FOREIGN KEY (`CATEGORIE_ID`) REFERENCES `categories` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `roles` (
...
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `users` (
...
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `users_roles` (
...
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
Prendiamo ad esempio lo script SQL che genera la tabella [PRODUITS] (righe 15-29):
- riga 16: [ID] è la chiave primaria (riga 23) con l'attributo [AUTO_INCREMENT] (riga 5). Ciò corrisponde alle annotazioni [@Id, @GeneratedValue(strategy = GenerationType.IDENTITY), @Column(name = ConfigJdbc.TAB_JPA_ID)] del campo [id] dell’entità JPA;
- riga 17: la definizione della colonna [DESCRIPTION] corrisponde all’annotazione [@Column(name = ConfigJdbc.TAB_PRODUITS_DESCRIPTION, length = 100)] del campo [description] dell’entità JPA;
- riga 18: la colonna [CATEGORIE_ID] è una chiave esterna della tabella [PRODUITS] sulla colonna [CATEGORIES.ID] (riga 26). Inoltre, questa chiave esterna presenta l’attributo [ON DELETE CASCADE]. Ciò corrisponde alle annotazioni [@ManyToOne(fetch = FetchType.LAZY), @JoinColumn(name = ConfigJdbc.TAB_PRODUITS_CATEGORIE_ID)] del campo [Produit.categorie] e all’annotazione [@OneToMany(fetch = FetchType.LAZY, mappedBy = "categorie", cascade = { CascadeType.ALL }), @CascadeOnDelete] del campo [Categorie.produits];
- riga 19: la definizione della colonna [NOM] corrisponde all'annotazione [@Column(name = ConfigJdbc.TAB_PRODUITS_NOM, unique = true, length = 30, nullable = false)] del campo [Produit.nom];
- riga 20: la definizione della colonna [PRIX] corrisponde all'annotazione [@Column(name = ConfigJdbc.TAB_PRODUITS_PRIX, nullable = false)] del campo [Produit.prix];
- righe 24-25: lo script crea tre indici per ciascuna delle colonne uniche della tabella;
Le tabelle generate non hanno un valore predefinito per il campo VERSIONING, mentre il codice Java si aspetta che ce ne sia uno. Se questo valore predefinito non è presente, alcuni test non vengono superati. Si aggiunge questo attributo nel modo seguente:
![]() |
![]() |
![]() |
Lo si fa per le cinque tabelle che hanno la colonna [VERSIONING]. Il valore predefinito non ha importanza. È sufficiente che esista. Successivamente, viene incrementato di 1 ad ogni modifica della riga a cui appartiene.
Fatto ciò, verificare che le seguenti configurazioni di esecuzione vadano a buon fine:
- [spring-jdbc-generic-04.JUnitTestDao], che verifica l’implementazione JDBC;
- [spring-jpa-generic-JUnitTestDao-hibernate-eclipselink] che verifica le implementazioni JPA Hibernate o Eclipselink (in questo caso sarà EclipseLink)
Entrambe le esecuzioni devono avere esito positivo.
9.2.6. Generazione delle tabelle con Hibernate
Creiamo le tabelle Hibernate con il seguente ambiente Eclipse:
![]() |
La generazione delle tabelle avviene tramite la configurazione di esecuzione denominata [generic-create-dbproduitscategories-hibernate] senza agente Java;
![]() | ![]() |
Lo script SQL del database generato da Hibernate è il seguente:
SET FOREIGN_KEY_CHECKS=0;
USE `dbproduitscategories`;
CREATE TABLE `categories` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `UK_7ajcg7japnxw846ru01damg8s` (`NOM`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `produits` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`DESCRIPTION` VARCHAR(100) COLLATE utf8_general_ci DEFAULT NULL,
`CATEGORIE_ID` BIGINT(20) NOT NULL,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRIX` DOUBLE NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `UK_hfvjn9lp7qoo5x79uu0ump3rf` (`NOM`) USING BTREE,
KEY `FK_p3foj9yrqnmi7856n9s8mbpue` (`CATEGORIE_ID`) USING BTREE,
CONSTRAINT `FK_p3foj9yrqnmi7856n9s8mbpue` FOREIGN KEY (`CATEGORIE_ID`) REFERENCES `categories` (`ID`)
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `roles` (
...
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `users` (
...
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `users_roles` (
...
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
Le tabelle generate sono le stesse poiché anche Hibernate ha utilizzato le annotazioni JPA. Per Hibernate, non ho trovato l'equivalente dell'annotazione EclipseLink [@OnCascadeDelete] che ha generato l'attributo SQL [ON DELTE CASCADE] sulla chiave esterna [PRODUITS.CATEGORIE_ID] (riga 25). È quindi necessario generare manualmente questo attributo poiché è necessario per i test:
![]() |
![]() |
![]() |
Occorre procedere allo stesso modo con le due chiavi esterne della tabella [USERS_ROLES]:
![]() |
Infine, come già fatto con l'implementazione EclipseLink, è necessario che le colonne [VERSIONING] delle cinque tabelle abbiano un valore predefinito:
![]() |
Fatto ciò, verificare che le seguenti configurazioni di esecuzione vadano a buon fine:
- [spring-jdbc-generic-04.JUnitTestDao], che verifica l’implementazione JDBC;
- [spring-jpa-generic-JUnitTestDao-hibernate-eclipselink] che verifica le implementazioni JPA Hibernate o Eclipselink (in questo caso si tratterà di Hibernate)
Entrambe le esecuzioni devono avere esito positivo.
9.2.7. Generazione delle tabelle con OpenJpa
Ripetiamo la procedura precedente con un'implementazione JPA OpenJpa:
![]() |
Nota: premere Alt-F5 e rigenerare tutti i progetti Maven;
Modifichiamo la classe [ConfigJpa] che configura il progetto [mysql-config-jpa-openjpa] nel modo seguente:
package generic.jpa.config;
import generic.jdbc.config.ConfigJdbc;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
@Import({ ConfigJdbc.class })
public class ConfigJpa {
// il provider JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
OpenJpaVendorAdapter openJpaVendorAdapter = new OpenJpaVendorAdapter();
openJpaVendorAdapter.setShowSql(false);
openJpaVendorAdapter.setDatabase(Database.MYSQL);
openJpaVendorAdapter.setGenerateDdl(true);
return openJpaVendorAdapter;
}
..
// EntityManagerFactory
@Bean
public EntityManagerFactory entityManagerFactory(JpaVendorAdapter jpaVendorAdapter, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(jpaVendorAdapter);
factory.setPackagesToScan(ENTITIES_PACKAGES);
Map<String, Object> mapJpaProperties = factory.getJpaPropertyMap();
mapJpaProperties.put("openjpa.jdbc.MappingDefaults",
"ForeignKeyDeleteAction=cascade,JoinForeignKeyDeleteAction=restrict");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
}
- righe 40-41: si crea una proprietà per OpenJPA che indica come generare le chiavi esterne durante la generazione delle tabelle. Senza questa proprietà, le chiavi esterne non vengono generate. L'attributo [ForeignKeyDeleteAction=cascade] consente di generare l'attributo [ON DELETE CASCADE] su queste chiavi esterne;
La generazione delle tabelle avviene tramite la configurazione di esecuzione denominata [generic-create-dbproduitscategories-openjpa], che dispone di due agenti Java;

- il primo agente Java è l'agente Spring già utilizzato con EclipseLink;
- il secondo agente Java è fornito da OpenJpa;
Lo script SQL del database generato è quindi il seguente:
SET FOREIGN_KEY_CHECKS=0;
USE `dbproduitscategories`;
CREATE TABLE `categories` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `U_CTGORIS_NOM` (`NOM`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `produits` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`DESCRIPTION` VARCHAR(100) COLLATE utf8_general_ci DEFAULT NULL,
`CATEGORIE_ID` BIGINT(20) DEFAULT NULL,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRIX` DOUBLE NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `U_PRODUTS_NOM` (`NOM`) USING BTREE,
KEY `CATEGORIE_ID` (`CATEGORIE_ID`) USING BTREE,
CONSTRAINT `produits_ibfk_1` FOREIGN KEY (`CATEGORIE_ID`) REFERENCES `categories` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `roles` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`NAME` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `U_ROLES_NAME` (`NAME`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `users` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`LOGIN` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`NAME` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PASSWORD` VARCHAR(60) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `U_USERS_LOGIN` (`LOGIN`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
CREATE TABLE `users_roles` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`VERSIONING` BIGINT(20) DEFAULT NULL,
`ROLE_ID` BIGINT(20) NOT NULL,
`USER_ID` BIGINT(20) NOT NULL,
PRIMARY KEY (`ID`) USING BTREE,
KEY `ROLE_ID` (`ROLE_ID`) USING BTREE,
KEY `USER_ID` (`USER_ID`) USING BTREE,
CONSTRAINT `users_roles_ibfk_2` FOREIGN KEY (`USER_ID`) REFERENCES `users` (`ID`) ON DELETE CASCADE,
CONSTRAINT `users_roles_ibfk_1` FOREIGN KEY (`ROLE_ID`) REFERENCES `roles` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
È lo stesso caso di EclipseLink. Si procederà quindi alle stesse correzioni sulle tabelle. Una volta fatto ciò, verificare che le seguenti configurazioni di esecuzione vadano a buon fine:
- [spring-jdbc-generic-04.JUnitTestDao], che verifica l’implementazione JDBC;
- [spring-jpa-generic-JUnitTestDao-openjpa], che verifica l’implementazione di JPA e OpenJpa;
Entrambe le esecuzioni devono avere esito positivo.
9.3. Generazione della base [dbproduits]
La base [dbproduits] viene utilizzata dai progetti [spring-jdbc-01 à 03]. È inoltre possibile generarla a partire da un'entità JPA.
![]() |
- in [1], i progetti Eclipse. Ci si troverà in una configurazione MySQL / EclipseLink. Il progetto di generazione della base [dbproduits] è [generic-create-dbproduits];
- in [2], la tabella [PRODUITS] da generare;
Nota: premere Alt-F5 e rigenerare tutti i progetti Maven;
9.3.1. Configurazione Maven
La configurazione Maven del progetto [generic-create-dbproduits] è la seguente:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-create-dbproduits</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>generic-create-dbproduits</name>
<description>création de la bases de données [dbproduits] à l'aide des annotations JPA</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- configurazione JPA del SGBD -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-config-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>spring.data.console.Main</start-class>
<java.version>1.7</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
C'è una sola dipendenza, alle righe 22-26, relativa al progetto che configura il livello JPA. In definitiva, le dipendenze sono le seguenti:
![]() |
9.3.2. La configurazione Spring
![]() |
La classe di configurazione Spring è la seguente:
package console;
import generic.jdbc.config.ConfigJdbc;
import generic.jpa.config.ConfigJpa;
import javax.persistence.EntityManagerFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@EnableJpaRepositories(basePackages = { "console" })
@Configuration
@Import({ ConfigJpa.class })
public class AppConfig {
// fonte dati
@Bean
public DataSource dataSource() {
// fonte dati TomcatJdbc
DataSource dataSource = new DataSource();
// configurazione accesso JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITS);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITS);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITS);
// connessioni inizialmente aperte
dataSource.setInitialSize(5);
// risultato
return dataSource;
}
// EntityManagerFactory
@Bean
public EntityManagerFactory entityManagerFactory(JpaVendorAdapter jpaVendorAdapter, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(jpaVendorAdapter);
factory.setPersistenceUnitName("generic-jpa-entities-dbproduits");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
}
- riga 18: si importano i bean della classe [ConfigJpa] (paragrafo 7.3);
- righe 22-35: si ridefinisce la fonte dati [dataSource]. In [ConfigJpa] la fonte dati è il database [dbproduitscategories]. In questo caso sarà il database [dbproduits];
- righe 38-46: si ridefinisce il bean [entityManagerFactory] della classe [ConfigJpa]. In questa classe, le entità JPA erano [Produit, Categorie]. Qui è solo [Produit] e non ha la stessa definizione presente nel progetto che configura il livello JPA;
- riga 42: per definire questa nuova entità JPA, si fa riferimento alle entità JPA definite nel file [META-INF/persistence.xml]:
![]() |
Il file [persistence.xml] è il seguente:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="generic-jpa-entities-dbproduits" transaction-type="RESOURCE_LOCAL">
<!-- entità JPA -->
<class>generic.jpa.entities.dbproduits.Produit</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
</persistence>
- riga 6: l'unica entità JPA;
- riga 4: il nome dell'unità di persistenza [generic-jpa-entities-dbproduits] a cui fa riferimento il bean [entityManagerFactory];
9.3.3. L'entità JPA [Produit]
![]() |
L'entità JPA è definita nel progetto [mysql-config-jpa-eclipselink] come segue:
package generic.jpa.entities.dbproduits;
import generic.jdbc.config.ConfigJdbc;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity(name="Produit1")
@Table(name = ConfigJdbc.TAB_PRODUITS)
public class Produit {
// campi
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = ConfigJdbc.TAB_PRODUITS_ID)
private int id;
@Column(name = ConfigJdbc.TAB_PRODUITS_NOM, unique = true, length = 30, nullable = false)
private String nom;
@Column(name = ConfigJdbc.TAB_PRODUITS_CATEGORIE, nullable = false)
private int categorie;
@Column(name = ConfigJdbc.TAB_PRODUITS_PRIX, nullable = false)
private double prix;
@Column(name = ConfigJdbc.TAB_PRODUITS_DESCRIPTION, length = 100, nullable = false)
private String description;
// costruttori
public Produit() {
}
public Produit(int id, String nom, int categorie, double prix, String description) {
this.id = id;
this.nom = nom;
this.categorie = categorie;
this.prix = prix;
this.description = description;
}
// getter e setter
...
}
Si tratta di una definizione JPA ormai diventata classica. Si notino semplicemente i seguenti punti:
- riga 12: all’entità è stato assegnato il nome [Produit1]. Per impostazione predefinita, il nome di un’entità corrisponde al nome della classe, in questo caso [Produit]. Tuttavia, poiché nello stesso progetto è presente un’altra entità JPA [Produit], è stato segnalato un errore prima ancora dell’esecuzione. L’errore è stato risolto in questo modo;
- riga 24: la categoria è qui un semplice numero;
- non ci sono relazioni tra le entità. Si tratta quindi di una situazione molto semplice;
9.3.4. La classe eseguibile
![]() |
La classe [CreateDatabase] è la seguente:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class CreateDataBase {
public static void main(String[] args) {
// è sufficiente istanziare il contesto Spring per creare le tabelle del database [dbproduits]
// è necessario anche almeno un Spring Data Repository, altrimenti non succede nulla
System.out.println("Travail en cours...");
new AnnotationConfigApplicationContext(AppConfig.class).close();
System.out.println("Travail terminé...");
}
}
Si tratta di un codice che abbiamo già incontrato.
9.3.5. Generazione EclipseLink
La tabella [PRODUITS] viene creata con la seguente configurazione di esecuzione:
![]() | ![]() |
I log della console sono i seguenti:
Ora torniamo al client [MyManager] e aggiorniamo la visualizzazione [1-2]:
![]() |
In [3] si vede che è stata generata una tabella. Ora verifichiamo il DDL (Domain Definition Language) del database:
SET FOREIGN_KEY_CHECKS=0;
USE `dbproduits`;
CREATE TABLE `produits` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`CATEGORIE` INTEGER(11) NOT NULL,
`DESCRIPTION` VARCHAR(100) COLLATE utf8_general_ci NOT NULL,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRIX` DOUBLE NOT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `NOM` (`NOM`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
Otteniamo effettivamente la tabella prevista. Per verificarlo, eseguiremo la seguente configurazione:
![]() | ![]() |
L'operazione dovrebbe andare a buon fine.
9.3.6. Generazione Hibernate
![]() | ![]() |
Nota: premere Alt-F5 e rigenerare tutti i progetti Maven;
La configurazione di esecuzione è la seguente:
![]() | ![]() |
Lo script SQL generato da Hibernate è il seguente:
USE `dbproduits`;
CREATE TABLE `produits` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`CATEGORIE` INTEGER(11) NOT NULL,
`DESCRIPTION` VARCHAR(100) COLLATE utf8_general_ci NOT NULL,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRIX` DOUBLE NOT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `UK_hfvjn9lp7qoo5x79uu0ump3rf` (`NOM`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;
9.3.7. Generazione OpenJpa
![]() | ![]() |
Nota: premere Alt-F5 e rigenerare tutti i progetti Maven;
La configurazione di esecuzione è la seguente:
![]() | ![]() |
Lo script SQL generato da OpenJpa è il seguente:
USE `dbproduits`;
CREATE TABLE `produits` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`CATEGORIE` INTEGER(11) NOT NULL,
`DESCRIPTION` VARCHAR(100) COLLATE utf8_general_ci NOT NULL,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRIX` DOUBLE NOT NULL,
PRIMARY KEY (`ID`) USING BTREE,
UNIQUE KEY `U_PRODUTS_NOM` (`NOM`) USING BTREE
) ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
;

















































