9. إنشاء قواعد بيانات من كيانات JPA
من الممكن إنشاء جداول قاعدة بيانات من كيانات JPA. سنقوم بتوضيح ذلك الآن. والغرض من ذلك هو التحقق من أن قاعدة البيانات التي تم إنشاؤها من كيانات JPA هي بالفعل القاعدة التي نريدها.
9.1. إعداد بيئة العمل
سنعمل أولاً مع تطبيق EclipseLink JPA [1].
![]() |
ثم نقوم بحذف الجداول من قاعدة بيانات MySQL [dbproduitscategories] باستخدام العميل [MyManager] (انظر القسم 23.5). نبدأ بحذف الجداول التي تحتوي على المفاتيح الخارجية [1-3]:
![]() |
ثم نكرر العملية مع الجداول الثلاثة المتبقية [4-6]:
![]() |
ونفعل الشيء نفسه مع الجدول [dbproduits] الذي تستخدمه مشاريع [spring-jdbc-01 إلى 03]:
![]() | ![]() |
بالإضافة إلى ذلك، يجب عليك استيراد مشروعي إنشاء قاعدة البيانات:
![]() |
- في [1]، قم باستيراد مشروع [generic-create-dbproduits]، الذي يمكن العثور عليه في [<examples>/spring-database-generic/spring-jpa] [2]؛
![]() |
- في [4]، قم باستيراد مشروع [generic-create-dbproduitscategories]، الذي يمكن العثور عليه في [<examples>/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. تكوين الربيع
![]() |
تقوم فئة [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 المستخدم):
// the provider JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
// Note: JPA entities and Eclipselink configuration are in the META-INF/persistence.xml file
EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter = new EclipseLinkJpaVendorAdapter();
eclipseLinkJpaVendorAdapter.setShowSql(false);
eclipseLinkJpaVendorAdapter.setDatabase(Database.MYSQL);
eclipseLinkJpaVendorAdapter.setGenerateDdl(true);
return eclipseLinkJpaVendorAdapter;
}
السطر 8 هو الأهم هنا. وهو موجود في جميع تطبيقات JPA المستخدمة. ويحدد أنه في حالة عدم وجود الجداول المرتبطة بكيانات JPA، يجب إنشاؤها. سنستخدم هذه الخاصية لإنشاء الجداول.
9.2.3. المستودعات
![]() |
واجهة [ProductsRepository] هي كما يلي:
package console;
import generic.jpa.entities.dbproduitscategories.Produit;
import org.springframework.data.repository.CrudRepository;
public interface ProduitsRepository extends CrudRepository<Produit, Long> {
}
سيؤدي إنشاء مثيل لهذه الواجهة إلى إنشاء مثيل لطبقة JPA. في الواقع، في السطر 7، تشير الواجهة إلى كيان JPA [Product]، مما سيؤدي إلى إنشاء مثيل لطبقة JPA. كان بإمكاننا استخدام أي واجهة [CrudRepository] تشير إلى أحد كيانات JPA. يمكننا أن نرى أنه على الرغم من أن [repository] تشير فقط إلى كيان JPA [Product]، يتم إنشاء جميع الجداول لجميع كيانات JPA.
9.2.4. الفئة القابلة للتنفيذ
![]() |
الفئة [CreateDatabase] هي كما يلي:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class CreateDataBase {
public static void main(String[] args) {
// simply instantiate the Spring context to create the database tables [dbproduitscategories]
// you also need at least one Spring Data Repository, otherwise nothing happens
System.out.println("Travail en cours...");
new AnnotationConfigApplicationContext(AppConfig.class).close();
System.out.println("Travail terminé...");
}
}
- السطر 11: نقوم بإنشاء مثيل لسياق Spring ثم نغلقه على الفور. يوجد في هذا السياق مكون [ProductsRepository] الذي يشير إلى كيان JPA [Product]. وهذا يكفي لإنشاء مثيل لطبقة JPA وبالتالي إنشاء الجداول في قاعدة البيانات [productcategories].
9.2.5. إنشاء الجداول باستخدام EclipseLink
نحن في التكوين التالي:
![]() |
- تم تكوين طبقة [JDBC] لقاعدة بيانات MySQL [dbproduitscategories]؛
- يتم تنفيذ طبقة [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) للقاعدة البيانات:
![]() | ![]() |
![]() |
يمكن أيضًا حفظ البرنامج النصي 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 الذي ينشئ الجدول [PRODUCTS] (الأسطر 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: يتوافق تعريف العمود [NAME] مع التعليق التوضيحي [@Column(name = ConfigJdbc.TAB_PRODUITS_NAME, unique = true, length = 30, nullable = false)] لحقل [Product.name]؛
- السطر 20: يتوافق تعريف العمود [PRICE] مع التعليق التوضيحي [@Column(name = ConfigJdbc.TAB_PRODUITS_PRIX, nullable = false)] لحقل [Product.price]؛
- السطران 24-25: ينشئ البرنامج النصي ثلاثة فهارس لكل عمود فريد في الجدول؛
لا تحتوي الجداول التي تم إنشاؤها على قيمة افتراضية لحقل VERSIONING، في حين أن كود Java يتوقع وجود واحدة. إذا كانت هذه القيمة الافتراضية مفقودة، فستفشل بعض الاختبارات. نضيف هذه السمة على النحو التالي:
![]() |
![]() |
![]() |
يتم ذلك بالنسبة للجداول الخمسة التي تحتوي على عمود [VERSIONING]. لا يهم القيمة الافتراضية؛ المهم هو وجود العمود فقط. ثم يتم زيادة قيمته بمقدار 1 في كل مرة يتم فيها تعديل الصف الذي ينتمي إليه.
بمجرد الانتهاء من ذلك، تحقق من اجتياز تكوينات الاختبار التالية:
- [spring-jdbc-generic-04.JUnitTestDao]، الذي يختبر تطبيق JDBC؛
- [spring-jpa-generic-JUnitTestDao-hibernate-eclipselink]، الذي يختبر تطبيقات Hibernate أو EclipseLink JPA (في هذه الحالة، سيكون 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 DELETE CASCADE] على المفتاح الأجنبي [PRODUCTS.CATEGORY_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
نكرر الإجراء السابق باستخدام تطبيق OpenJpa JPA:
![]() |
ملاحظة: اضغط على 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 {
// the 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();
}
}
- السطران 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]، الذي يختبر تطبيق OpenJPA JPA؛
يجب أن تنجح كلتا العمليتين.
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>
<!-- configuration JPA of 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 هي كما يلي:
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 {
// data source
@Bean
public DataSource dataSource() {
// data source TomcatJdbc
DataSource dataSource = new DataSource();
// configuration access JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITS);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITS);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITS);
// initially open connections
dataSource.setInitialSize(5);
// result
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 هي [Product، Category]. هنا، هي [Product] فقط، ولا تحمل نفس التعريف الموجود في المشروع الذي يهيئ طبقة 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">
<!-- entities 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 [Product]
![]() |
يتم تعريف كيان 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 {
// fields
@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;
// manufacturers
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;
}
// getters and setters
...
}
هذا تعريف JPA أصبح الآن معيارًا. لاحظ النقاط التالية:
- السطر 12: قمنا بتسمية الكيان باسم [Product1]. بشكل افتراضي، يكون اسم الكيان هو اسم الفئة، وهو في هذه الحالة [Product]. ولكن، نظرًا لوجود كيان JPA آخر باسم [Product] في نفس المشروع، تم الإبلاغ عن خطأ قبل أن يبدأ التنفيذ. وقد قمنا بحل المشكلة على النحو التالي؛
- السطر 24: الفئة هنا هي مجرد رقم؛
- لا توجد علاقات بين الكيانات. لذلك، لدينا حالة بسيطة للغاية؛
9.3.4. الفئة القابلة للتنفيذ
![]() |
الفئة [CreateDatabase] هي كما يلي:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class CreateDataBase {
public static void main(String[] args) {
// simply instantiate the Spring context to create the database tables [dbproduits]
// you also need at least one Spring Data Repository, otherwise nothing happens
System.out.println("Travail en cours...");
new AnnotationConfigApplicationContext(AppConfig.class).close();
System.out.println("Travail terminé...");
}
}
هذا كود رأيناه من قبل.
9.3.5. إنشاء EclipseLink
يتم إنشاء الجدول [PRODUCTS] باستخدام التكوين التالي لوقت التشغيل:
![]() | ![]() |
سجلات وحدة التحكم هي كما يلي:
الآن، لنعد إلى عميل [MyManager] ونقوم بتحديث العرض [1-2]:
![]() |
في [3]، يمكننا أن نرى أنه تم إنشاء جدول. والآن دعونا نتحقق من لغة تعريف المجال (DDL) للقاعدة البيانات:
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'
;

















































