Skip to content

8. Spring Data JPA OpenJpa

8.1. Introduction

ما در حال استفاده مجدد از معماری قبلی هستیم که اکنون آن را با یک لایه JPA / OpenJpa پیاده‌سازی می‌کنیم.

8.2. راه‌اندازی محیط کاری

با استفاده از STS، پروژه‌های [myql-config-jpa-eclipselink] و [1-4] را از حالت فشرده خارج کنید:

سپس پروژه [mysl-config-jpa-openjpa] [5] را که در پوشه [<exemples>/spring-database-config/mysql/eclipse] [6] قرار دارد، وارد کنید:

پس از انجام این کار، محیط Maven را برای تمام پروژه‌ها در [Package Explorer] ریست کنید (Alt-F5):

 

سپس، برای بررسی محیط کاری، پیکربندی ساخت با نام [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>
  • خطوط ۵–۷: آرتیفکت Maven تولید شده توسط این پروژه. این همان آرتیفکت پروژه [mysql-config-jpa-hibernate] است. این بدان معناست که در هر زمان تنها یکی از این پروژه‌ها می‌تواند فعال باشد؛
  • خطوط ۱۰–۱۴: پروژهٔ والد Maven، که نسخه‌های اکثر وابستگی‌های مورد نیاز پروژه را مشخص می‌کند؛
  • خطوط ۱۹–۲۳: کتابخانه OpenJpa؛
  • خطوط 26–29: کتابخانه Spring Data؛
  • خطوط ۳۲–۳۴: پروژه پیکربندی لایه JPA به پروژه پیکربندی لایه JDBC متکی است، که در میان موارد دیگر، درایور JDBC برای SGBD در حال استفاده و جزئیات پایگاه داده مورد استفاده؛
  • خطوط ۳۵–۴۰: پروژه پیکربندی برای لایه 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 است. ما فقط به تفاوت‌ها می‌پردازیم:

  • خطوط ۲۳–۳۰: بیون [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>
  • خط ۴: واحد پایداری متصل به پایگاه داده [dbproduitscategories]. این واحد می‌تواند هر نامی داشته باشد (ویژگی name);
  • خطوط ۶–۱۰: پنج موجودیت JPA که باید مدیریت شوند؛
  • خطوط ۱۳–۱۷: یک واحد پایداری دیگر متصل به پایگاه داده [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 توسط OpenJpa غنی‌سازی (woven) شوند، باید برنامه‌های جاوا یا تست‌های JUnit با استفاده از یک عامل جاوا اجرا شوند. این کار پیش از بارگذاری این اشیاء توسط JVM و [http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html]، آن‌ها را غنی‌سازی می‌کند. برای مثال، بیایید به پیکربندی تست [JUnitTestDao] نگاهی بیندازیم:

  • در زبانه [Arguments] [1]، ارجاع به عامل جاوا برای JVM با استفاده از دستورات [2] مشخص شده است. عامل جاوا آرشیو [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]: ۳۶٫۰۹ ثانیه;
  • در [4], [JUnitTestPushTheLimits-OpenJpa]: 80.394 ثانیه;

نتایج کنسول به‌دست‌آمده برای تست [JUnitTestProxies] به شرح زیر است:

Vidage de la base de données --------------------------------
doNothing
Vidage de la base de données --------------------------------
getShortCategoriesByName1 --------------------------------
Catégorie de type : PROXY
Catégorie :
Exception : java.lang.NullPointerException, Message : null
Vidage de la base de données --------------------------------
getLongCategoriesByName1 --------------------------------
Catégorie de type : POJO
Catégorie :
1
Vidage de la base de données --------------------------------
getShortProduitsByName1 --------------------------------
Produit de type : PROXY
Nom de la catégorie du produit :
Exception : java.lang.NullPointerException, Message : null
Vidage de la base de données --------------------------------
getLongProduitsByName1 --------------------------------
Produit de type : POJO
Nom de la catégorie du produit :
categorie[0]

در اینجا می‌بینیم که هنگام دسترسی به فیلد [Categorie.produits] یک دسته‌بندی از نوع PROXY و فیلد [Produit.categorie] یک محصول از نوع PROXY، در هر دو مورد (خطوط ۷ و ۱۷) یک نشانگر null وجود دارد.