8. Spring Data JPA OpenJpa
8.1. مقدمة
نستأنف البنية السابقة التي نقوم الآن بتنفيذها باستخدام طبقة JPA / OpenJpa.
![]() |
8.2. إعداد بيئة العمل
باستخدام STS، قم بتنزيل المشروع [myql-config-jpa-eclipselink] [1-4]:
![]() |
ثم قم باستيراد المشروع [mysl-config-jpa-openjpa] [5] الموجود في المجلد [<exemples>/spring-database-config/mysql/eclipse] [6]:
![]() |
بعد ذلك، أعد ضبط بيئة Maven (Alt-F5) لجميع المشاريع الموجودة في [Package Explorer]:
![]() |
ثم، للتحقق من بيئة العمل، قم بتنفيذ التكوين المسمى [spring-jpa-generic-JUnitTestDao-openjpa]:
![]() | ![]() |
تقوم هذه التهيئة بتشغيل الاختبار [JUnitTestDao]. يجب أن ينجح هذا الاختبار:
![]() |
8.3. مشروع تكوين الطبقة JPA
![]() |
يهدف هذا المشروع إلى تكوين الطبقة JPA في البنية التالية:
![]() |
8.3.1. تكوين Maven
المشروع هو مشروع Maven ويتم تكوينه بواسطة الملف [pom.xml] التالي:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-config-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>configuration mysql openjpa</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- التبعيات المتغيرة ********************************************** -->
<!-- مزود JPA -->
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.3.0</version>
</dependency>
<!-- التبعيات الثابتة ********************************************** -->
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- التكوين الموروث JDBC -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-config-jdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<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>
- الأسطر 5-7: عنصر Maven الذي تم إنشاؤه بواسطة هذا المشروع. وهو نفس العنصر الخاص بمشروع [mysql-config-jpa-hibernate]. وهذا يعني أنه لا يمكن أن يكون سوى مشروع واحد من هذين المشروعين نشطًا في وقت واحد؛
- الأسطر 10-14: مشروع Maven الأصلي الذي يحدد إصدار معظم التبعيات اللازمة للمشروع؛
- الأسطر 19-23: مكتبة OpenJpa؛
- الأسطر 26-29: مكتبة Spring Data؛
- الأسطر 32-34: يعتمد مشروع تكوين الطبقة JPA على مشروع تكوين الطبقة JDBC الذي يحدد، من بين أمور أخرى، برنامج التشغيل JDBC الخاص بـ SGBD المستخدم وبيانات الاتصال بقاعدة البيانات المطلوب استخدامها؛
- الأسطر 35-40: يتضمن مشروع تكوين الطبقة JDBC المكتبة [Spring JDBC] التي تم استبدالها هنا بالمكتبة [Spring Data JPA]. لذلك يُنصح بعدم تضمينها في تبعيات المشروع. ومع ذلك، فإن بقاءها لن يتسبب في حدوث أخطاء؛
وفي النهاية، تكون التبعيات كما يلي:
![]() |
8.3.2. تكوين Spring
![]() |
تقوم الفئة [ConfigJpa] بتكوين مشروع Spring على النحو التالي:
package generic.jpa.config;
import generic.jdbc.config.ConfigJdbc;
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;
}
// حزم كيانات JPA
public final static String[] ENTITIES_PACKAGES = { "generic.jpa.entities.dbproduitscategories" };
// مصدر البيانات
@Bean
public DataSource dataSource() {
// مصدر البيانات TomcatJdbc
DataSource dataSource = new DataSource();
// تكوين الوصول JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITSCATEGORIES);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITSCATEGORIES);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITSCATEGORIES);
// الاتصالات المفتوحة في البداية
dataSource.setInitialSize(5);
// النتيجة
return dataSource;
}
// EntityManagerFactory
@Bean
public EntityManagerFactory entityManagerFactory(JpaVendorAdapter jpaVendorAdapter, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(jpaVendorAdapter);
factory.setPackagesToScan(ENTITIES_PACKAGES);
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
// مدير المعاملات
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
هذا التكوين مشابه للتكوين الموضح بالتفصيل في الفقرة 6.3.2، الخاص بتنفيذ Hibernate JPA. سنكتفي هنا بتوضيح الاختلافات فقط:
- الأسطر 23-30: يتم الآن تنفيذ الكائن [jpaVendorAdapter] باستخدام OpenJpa؛
8.4. الملف [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-dbproduitscategories" transaction-type="RESOURCE_LOCAL">
<!-- الكيانات JPA -->
<class>generic.jpa.entities.dbproduitscategories.Categorie</class>
<class>generic.jpa.entities.dbproduitscategories.Produit</class>
<class>generic.jpa.entities.dbproduitscategories.User</class>
<class>generic.jpa.entities.dbproduitscategories.Role</class>
<class>generic.jpa.entities.dbproduitscategories.UserRole</class>
<exclude-unlisted-classes />
</persistence-unit>
<persistence-unit name="generic-jpa-entities-dbproduits" transaction-type="RESOURCE_LOCAL">
<!-- الكيانات JPA -->
<class>generic.jpa.entities.dbproduits.Produit</class>
<exclude-unlisted-classes />
</persistence-unit>
</persistence>
- السطر 4: وحدة الاستمرارية المرتبطة بقاعدة البيانات [dbproduitscategories]. يمكن أن تحمل أي اسم (السمة name)؛
- الأسطر 6-10: الكيانات الخمسة JPA المطلوب إدارتها؛
- الأسطر 13-17: وحدة استمرارية أخرى مرتبطة بقاعدة البيانات [dbproduits]. تتيح OpenJpa وجود ملف استمرارية يحتوي على عدة وحدات استمرارية. أما EclipseLink فلا تتيح ذلك. تجدر الإشارة إلى أنه مع Hibernate، لم يتم استخدام ملف استمرارية؛
8.5. طبقة الاختبارات
![]() |
![]() |
الاختبارات المذكورة أعلاه مطابقة لتلك الموجودة في تطبيقات Spring JDBC و Spring JPA Hibernate و Spring JPA EclipseLink. يرجى الرجوع إلى الصفحات التالية إذا لزم الأمر:
- [JUnitTestCheckArguments]: الفقرة 4.11.1؛
- [JUnitTestDao]: الفقرة 4.11.2؛
- [JUnitTestPushTheLimits]: الفقرة 4.11.3؛
- [JUnitTestProxies]: الفقرة 6.4.5؛
إعدادات التشغيل التي يجب استخدامها هي التالية:
![]() | ![]() |
![]() | ![]() |
لكي يتم إثراء الكيانات JPA (woven) بواسطة OpenJpa، يجب تشغيل تطبيقات Java أو اختبارات JUnit باستخدام وكيل Java. وسيقوم هذا الوكيل بتعزيز الكيانات JPA قبل أن يتم تحميلها بواسطة JVM و[http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html]. لنلقِ نظرة، على سبيل المثال، على تكوين الاختبار [JUnitTestDao]:
![]() |
- في علامة التبويب [Arguments] [1]، يتم تحديد مرجع وكيل Java إلى JVM وفقًا لصيغة [2]. وكيل Java هو الأرشيف [openjpa-<version>.jar] الموجود في المجلد [<m2-repo>/org/apache/openjpa/<version>]. يتم تحديد المجلد <m2-repo> في إعدادات Eclipse ([3] أدناه):
![]() |
في [2] أعلاه، تم استخدام متغير [M2_REPO] الذي حدده المستخدم:
![]() |
وقد أُعطيت المتغير [M2_REPO] القيمة الظاهرة في [3].
النتائج التي تم الحصول عليها لاختباري [JUnitTestDao] و [JUnitTestPushTheLimits] هي كما يلي:
![]() |
![]() |
![]() |
- في [1] و [JUnitTestPushTheLimits-EclipseLink]: 70,583 ثانية؛
- في [2]، [JUnitTestPushTheLimits-Hibernate]: 78,945 ثانية؛
- في [3]، [JUnitTestPushTheLimits-JDBC]: 36,09 ثانية؛
- في [4]، [JUnitTestPushTheLimits-OpenJpa]: 80,394 ثانية؛
النتائج التي تم الحصول عليها من وحدة التحكم لاختبار [JUnitTestProxies] هي كما يلي:
نلاحظ هنا أنه عند الوصول إلى الحقل [Categorie.produits] لفئة من النوع PROXY وإلى الحقل [Produit.categorie] لمنتج من النوع PROXY، يكون لدينا مؤشر null في كلتا الحالتين (السطران 7 و17).























