9. Створення баз даних на основі сутностей JPA
Можна створити таблиці бази даних на основі сутностей JPA. Саме це ми зараз і продемонструємо. Мета полягає в тому, щоб перевірити, чи база даних, згенерована на основі сутностей JPA, дійсно відповідає нашим вимогам.
9.1. Налаштування робочого середовища
Спочатку ми будемо працювати з реалізацією JPA, EclipseLink та [1].
![]() |
Потім видаляємо таблиці з бази даних MySQL, [dbproduitscategories] за допомогою клієнта [MyManager] (див. параграф 23.5). Спочатку видаляємо таблиці, що містять зовнішні ключі [1-3]:
![]() |
Потім продовжуємо з трьома таблицями, що залишилися, [4-6]:
![]() |
Те саме робимо з таблицею [dbproduits], яка використовується проектами [spring-jdbc-01 à 03]:
![]() | ![]() |
Крім того, потрібно імпортувати обидва проекти для створення обох баз даних:
![]() |
- у [1] імпортується проект [generic-create-dbproduits], який знаходиться у [<exemples>/spring-database-generic/spring-jpa] [2];
![]() |
- у [4] імпортується проект [generic-create-dbproduitscategories], який знаходиться у [<exemples>/spring-database-generic/spring-jpa] та [5];
Примітка: натисніть Alt-F5 і перегенеруйте всі проекти Maven;
9.2. Генерація бази даних [dbproduitscategories]
![]() |
9.2.1. Конфігурація Maven
Файл [pom.xml] цього проєкту має такий вигляд:
<?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>
- рядки 22–26: залежність від проєкту [spring-jpa-generic], розглянутого в розділі 6.4;
- рядки 28–32: залежність від weaver, який буде використовуватися для збагачення сутностей JPA реалізаціями EclipseLink та OpenJpa. Ця залежність не потрібна у файлі [pom.xml], але його JAR-файл буде використовуватися як Java-агент. Включення залежності у файл [pom.xml] гарантує, що JAR-файл буде доступний;
У підсумку залежності мають такий вигляд:
![]() |
9.2.2. Конфігурація Spring
![]() |
Клас [AppConfig] налаштовує проект 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 {
}
- рядок 10: клас отримує біни з класу [ConfigJpa]. Нагадаємо, що цей клас працює з сутностями JPA з бази даних [dbproduitscategories] (див. параграф 6.3);
- рядок 11: оголошується, що пакет [console] має бути просканований для пошуку екземплярів [CrudRepository];
У класі [ConfigJpa] міститься такий бін (залежить від використовуваної реалізації JPA):
// провайдер JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
// Примітка: сутності JPA та конфігурація Eclipselink містяться у файлі META-INF/persistence.xml
EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter = new EclipseLinkJpaVendorAdapter();
eclipseLinkJpaVendorAdapter.setShowSql(false);
eclipseLinkJpaVendorAdapter.setDatabase(Database.MYSQL);
eclipseLinkJpaVendorAdapter.setGenerateDdl(true);
return eclipseLinkJpaVendorAdapter;
}
Тут важливим є рядок 8. Він присутній у всіх використовуваних реалізаціях JPA. Він вказує, що якщо таблиці, пов’язані з сутностями JPA, не існують, їх слід створити. Ми скористаємося цією властивістю для генерації таблиць.
9.2.3. Репозиторії
![]() |
Інтерфейс [ProduitsRepository] має такий вигляд:
package console;
import generic.jpa.entities.dbproduitscategories.Produit;
import org.springframework.data.repository.CrudRepository;
public interface ProduitsRepository extends CrudRepository<Produit, Long> {
}
Саме його інстанціювання спричинить інстанціювання шару JPA. Дійсно, у рядку 7 інтерфейс посилається на сутності JPA та [Produit], що змусить створити екземпляр шару JPA. Можна було б вказати будь-який інтерфейс [CrudRepository], що посилається на одну з сутностей JPA. Дійсно, можна помітити, що, хоча [repository] посилається лише на сутності JPA та [Produit], генеруються всі таблиці всіх сутностей JPA.
9.2.4. Виконуваний клас
![]() |
Клас [CreateDatabase] має такий вигляд:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class CreateDataBase {
public static void main(String[] args) {
// достатньо створити екземпляр контексту Spring, щоб створити таблиці бази даних [dbproduitscategories]
// також потрібно принаймні одне сховище Spring Data, інакше нічого не відбудеться
System.out.println("Travail en cours...");
new AnnotationConfigApplicationContext(AppConfig.class).close();
System.out.println("Travail terminé...");
}
}
- рядок 11: створюється екземпляр контексту Spring, щоб одразу ж його закрити. У цьому контексті є бін [ProduitsRepository], який посилається на сутності JPA та [Produit]. Цього достатньо для створення екземпляра шару JPA і, отже, для генерації таблиць бази даних [dbproduitscategories].
9.2.5. Створення таблиць за допомогою EclipseLink
Ми маємо таку конфігурацію:
![]() |
- шар [JDBC] налаштований для бази даних [dbproduitscategories] з MySQL;
- шар [JPA] реалізовано з використанням EclipseLink;
- база даних [dbproduitscategories] не містить таблиць;
Примітка: натисніть Alt-F5 і перегенеруйте всі проекти Maven;
Використовується така конфігурація виконання:
![]() |
- у [1-2] ця конфігурація виконання вимагає наявності агента Java для успішного проходження тесту. Залежно від обставин, EclipseLink не завжди потребує цього агента, але в даному випадку виконання завершиться невдало, якщо його немає. Цей агент не є агентом EclipseLink, а агентом Spring. Він надається залежністю:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<scope>runtime</scope>
</dependency>
зазначена у файлі [pom.xml] проекту. Агент знаходиться у файлі [<m2-repo>/org/springframework/spring-instrument/4.1.6.RELEASE/spring-instrument-4.1.6.RELEASE.jar], де <m2-repo> — це локальне сховище Maven;
Виконання дає такий результат:
![]() |
У файлі [3] видно, що таблиці було згенеровано. Тепер перевіримо файл DDL (Domain Definition Language) бази даних:
![]() | ![]() |
![]() |
Скрипт SQL для генерації таблиць також можна зберегти у файлі [1].
![]() | ![]() ![]() |
Створений скрипт SQL має такий вигляд:
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'
;
Розглянемо, наприклад, скрипт SQL, який генерує таблицю [PRODUITS] (рядки 15–29):
- рядок 16: [ID] є первинним ключем (рядок 23) з атрибутом [AUTO_INCREMENT] (рядок 5). Це відповідає анотаціям [@Id, @GeneratedValue(strategy = GenerationType.IDENTITY), @Column(name = ConfigJdbc.TAB_JPA_ID)] поля [id] сутності JPA;
- рядок 17: визначення стовпця [DESCRIPTION] відповідає анотації [@Column(name = ConfigJdbc.TAB_PRODUITS_DESCRIPTION, length = 100)] поля [description] сутності JPA;
- рядок 18: стовпець [CATEGORIE_ID] є зовнішнім ключем таблиці [PRODUITS] щодо стовпця [CATEGORIES.ID] (рядок 26). Крім того, цей зовнішній ключ має атрибут [ON DELETE CASCADE]. Це відповідає анотаціям [@ManyToOne(fetch = FetchType.LAZY), @JoinColumn(name = ConfigJdbc.TAB_PRODUITS_CATEGORIE_ID)] поля [Produit.categorie] та анотації [@OneToMany(fetch = FetchType.LAZY, mappedBy = "categorie", cascade = { CascadeType.ALL }), @CascadeOnDelete] поля [Categorie.produits];
- рядок 19: визначення стовпця [NOM] відповідає анотації [@Column(name = ConfigJdbc.TAB_PRODUITS_NOM, unique = true, length = 30, nullable = false)] поля [Produit.nom];
- рядок 20: визначення стовпця [PRIX] відповідає анотації [@Column(name = ConfigJdbc.TAB_PRODUITS_PRIX, nullable = false)] поля [Produit.prix];
- рядки 24–25: скрипт створює три індекси для кожного з унікальних стовпців таблиці;
У створених таблицях відсутнє значення за замовчуванням для поля VERSIONING, тоді як код Java очікує, що воно має бути. Якщо це значення за замовчуванням відсутнє, деякі тести не проходять. Цей атрибут додається наступним чином:
![]() |
![]() |
![]() |
Це робиться для п’яти таблиць, які мають стовпець [VERSIONING]. Значення за замовчуванням не має значення. Воно просто має бути присутнім. Потім його збільшують на 1 при кожній зміні рядка, до якого воно належить.
Після цього переконайтеся, що виконуються такі конфігурації виконання:
- [spring-jdbc-generic-04.JUnitTestDao], що перевіряє реалізацію JDBC;
- [spring-jpa-generic-JUnitTestDao-hibernate-eclipselink], що тестує реалізації JPA Hibernate або Eclipselink (у даному випадку це буде EclipseLink)
Обидва запуски мають завершитися успішно.
9.2.6. Створення таблиць за допомогою Hibernate
Ми створюємо таблиці Hibernate у такому середовищі Eclipse:
![]() |
Генерація таблиць здійснюється за допомогою конфігурації виконання з назвою [generic-create-dbproduitscategories-hibernate] без Java-агента;
![]() | ![]() |
Скрипт SQL для бази даних, згенерованої Hibernate, має такий вигляд:
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'
;
Згенеровані таблиці є однаковими, оскільки Hibernate також використовував анотації JPA. Для Hibernate я не знайшов еквівалента анотації EclipseLink [@OnCascadeDelete], яка згенерувалаатрибут SQL [ON DELTE CASCADE] для зовнішнього ключа [PRODUITS.CATEGORIE_ID] (рядок 25). Тому цей атрибут потрібно згенерувати вручну, оскільки він необхідний для тестування:
![]() |
![]() |
![]() |
Те саме потрібно зробити з двома зовнішніми ключами таблиці [USERS_ROLES]:
![]() |
Нарешті, як це було зроблено з реалізацією EclipseLink, стовпці [VERSIONING] у п’яти таблицях повинні мати значення за замовчуванням:
![]() |
Після цього переконайтеся, що виконуються такі конфігурації:
- [spring-jdbc-generic-04.JUnitTestDao], що перевіряє реалізацію JDBC;
- [spring-jpa-generic-JUnitTestDao-hibernate-eclipselink], що тестує реалізації JPA — Hibernate або Eclipselink (у даному випадку — Hibernate)
Обидва запуски мають завершитися успішно.
9.2.7. Генерація таблиць за допомогою OpenJpa
Повторюємо попередню процедуру з реалізацією JPA OpenJpa:
![]() |
Примітка: натисніть Alt-F5 і перегенеруйте всі проекти Maven;
Ми змінюємо клас [ConfigJpa], який налаштовує проект [mysql-config-jpa-openjpa], наступним чином:
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 {
// провайдер 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();
}
}
- рядки 40–41: створюємо властивість для OpenJPA, яка вказує, як генерувати зовнішні ключі під час створення таблиць. Без цієї властивості зовнішні ключі не генеруються. Атрибут [ForeignKeyDeleteAction=cascade] дозволяє генерувати атрибут [ON DELETE CASCADE] для цих зовнішніх ключів;
Генерація таблиць здійснюється за допомогою конфігурації виконання з назвою [generic-create-dbproduitscategories-openjpa], яка має два Java-агенти;

- перший Java-агент — це агент Spring, який вже використовувався з EclipseLink;
- другий Java-агент надається OpenJpa;
Скрипт SQL із згенерованої бази має такий вигляд:
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'
;
Це те саме, що й у випадку з EclipseLink. Тому до таблиць слід внести ті самі виправлення. Після цього перевірте, чи проходять такі конфігурації виконання:
- [spring-jdbc-generic-04.JUnitTestDao], що перевіряє реалізацію JDBC;
- [spring-jpa-generic-JUnitTestDao-openjpa], що перевіряє реалізацію JPA та OpenJpa;
Обидва запуски повинні завершитися успішно.
9.3. Створення бази даних [dbproduits]
База [dbproduits] використовується проектами [spring-jdbc-01 à 03]. Її також можна створити на основі сутності JPA.
![]() |
- у [1] — проекти Eclipse. Ми перебуватимемо в конфігурації MySQL / EclipseLink. Проектом для генерації бази даних [dbproduits] є [generic-create-dbproduits];
- у [2] — таблиця [PRODUITS], яку потрібно згенерувати;
Примітка: натисніть Alt-F5 і перегенеруйте всі проекти Maven;
9.3.1. Конфігурація Maven
Конфігурація Maven для проєкту [generic-create-dbproduits] така:
<?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>
<!-- конфігурація JPA для 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>
Є лише одна залежність (рядки 22–26) від проєкту, що налаштовує рівень JPA. У підсумку залежності є такими:
![]() |
9.3.2. Конфігурація Spring
![]() |
Клас конфігурації Spring має такий вигляд:
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 {
// джерело даних
@Bean
public DataSource dataSource() {
// джерело даних TomcatJdbc
DataSource dataSource = new DataSource();
// конфігурація доступу JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITS);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITS);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITS);
// спочатку відкриті з'єднання
dataSource.setInitialSize(5);
// результат
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();
}
}
- рядок 18: імпортуються біни класу [ConfigJpa] (розділ 7.3);
- рядки 22–35: перевизначається джерело даних [dataSource]. У [ConfigJpa] джерелом даних є база [dbproduitscategories]. Тут це буде база [dbproduits];
- рядки 38–46: переопределяется bean [entityManagerFactory] класу [ConfigJpa]. У цьому класі сутності JPA були [Produit, Categorie]. Тут це лише [Produit], і вона не має того самого визначення, що й у проєкті, який налаштовує шар JPA;
- рядок 42: для визначення цієї нової сутності JPA використовується посилання на сутності JPA, визначені у файлі [META-INF/persistence.xml]:
![]() |
Файл [persistence.xml] має такий вигляд:
<?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">
<!-- об’єкти JPA -->
<class>generic.jpa.entities.dbproduits.Produit</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
</persistence>
- рядок 6: єдина суть JPA;
- рядок 4: ім’я одиниці збереження [generic-jpa-entities-dbproduits], на яку є посилання в біні [entityManagerFactory];
9.3.3. Ентітет JPA [Produit]
![]() |
Суть JPA визначена в проєкті [mysql-config-jpa-eclipselink] наступним чином:
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 {
// поля
@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;
// конструктори
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 та setter
...
}
Це визначення JPA, яке на сьогодні стало класичним. Звернемо увагу лише на такі моменти:
- рядок 12: об’єкту присвоєно ім’я [Produit1]. За замовчуванням ім’ям об’єкта є назва класу, у даному випадку [Produit]. Однак, оскільки в тому самому проєкті існує інша суть JPA [Produit], ще до початку виконання було виявлено помилку. Її було усунуто таким чином;
- рядок 24: категорія тут — це просто номер;
- між об’єктами немає взаємозв’язків. Отже, маємо дуже просту ситуацію;
9.3.4. Виконуваний клас
![]() |
Клас [CreateDatabase] має такий вигляд:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class CreateDataBase {
public static void main(String[] args) {
// достатньо створити екземпляр контексту Spring, щоб створити таблиці бази даних [dbproduits]
// також потрібно принаймні одне сховище Spring Data, інакше нічого не відбудеться
System.out.println("Travail en cours...");
new AnnotationConfigApplicationContext(AppConfig.class).close();
System.out.println("Travail terminé...");
}
}
Це код, з яким ми вже стикалися.
9.3.5. Генерація EclipseLink
Таблиця [PRODUITS] створюється з такими параметрами виконання:
![]() | ![]() |
Журнали консолі мають такий вигляд:
Тепер повернемося до клієнта [MyManager] і оновимо відображення [1-2]:
![]() |
У [3] видно, що таблиця була згенерована. Тепер перевіримо DDL (Domain Definition Language) бази даних:
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'
;
Ми дійсно отримуємо очікувану таблицю. Щоб це перевірити, виконаємо таку конфігурацію:
![]() | ![]() |
Вона має виконатися успішно.
9.3.6. Генерація Hibernate
![]() | ![]() |
Примітка: натисніть Alt-F5 і перегенеруйте всі проекти Maven;
Конфігурація виконання така:
![]() | ![]() |
Скрипт SQL, згенерований Hibernate, має такий вигляд:
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. Генерація OpenJpa
![]() | ![]() |
Примітка: натисніть Alt-F5 і перегенеруйте всі проекти Maven;
Конфігурація виконання така:
![]() | ![]() |
Скрипт SQL, згенерований OpenJpa, має такий вигляд:
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'
;

















































