مرحبًا بك في دليل مثال Spring ORM. اليوم سنلقي نظرة على مثال Spring ORM باستخدام إدارة المعاملات Hibernate JPA. سأريك مثالًا بسيطًا جدًا على تطبيق مستقل من Spring مع الميزات التالية.
- حقن التبعية (التعليق @Autowired)
- مدير الكيان JPA (المقدم من Hibernate)
- الطرق التي تحمل علامة تجارية (@Transactional)
مثال Spring ORM
لقد استخدمت قاعدة البيانات في الذاكرة لمثال Spring ORM ، لذا لا حاجة لإعداد أي قاعدة بيانات (ولكن يمكنك تغييرها إلى أي قاعدة بيانات أخرى في قسم مصدر البيانات في spring.xml). هذا تطبيق مستقل لـ Spring ORM لتقليل جميع التبعيات (لكن يمكنك بسهولة تحويله إلى مشروع ويب من خلال التكوين إذا تعرفت على Spring). NOTE: للحصول على أسلوب حل المشكلة لـ Spring AOP القائم على المعاملات (بدون تعليق @Transactional) يرجى مراجعة هذا البرنامج التعليمي: إدارة المعاملات بواسطة Spring ORM AOP. تظهر الصورة أدناه مشروع مثالنا النهائي لـ Spring ORM.
لنلخص كل من مكونات مشروع مثال Spring ORM بشكل فردي.
تبعيات Maven لـ Spring ORM
فيما يلي ملف pom.xml النهائي الذي يحتوي على تبعيات Spring ORM. لقد استخدمنا Spring 4 و Hibernate 4 في مثالنا لـ Spring ORM.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hu.daniel.hari.learn.spring</groupId>
<artifactId>Tutorial-SpringORMwithTX</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<!-- Generic properties -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<!-- SPRING & HIBERNATE / JPA -->
<spring.version>4.0.0.RELEASE</spring.version>
<hibernate.version>4.1.9.Final</hibernate.version>
</properties>
<dependencies>
<!-- LOG -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- JPA Vendor -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- IN MEMORY Database and JDBC Driver -->
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
- نحتاج
spring-context
وspring-orm
كتبعيات لـ Spring. - نستخدم
hibernate-entitymanager
لـ Hibernate كتنفيذ لـ JPA.hibernate-entitymanager
معتمد علىhibernate-core
وهذا السبب في عدم ضرورة وضع hibernate-core في ملف pom.xml بشكل صريح. إنه يتم جلبه إلى مشروعنا من خلال تبعيات Maven. - نحتاج أيضًا إلى محرك JDBC كتبعي للوصول إلى قاعدة البيانات. نستخدم HSQLDB التي تحتوي على محرك JDBC وقاعدة بيانات في الذاكرة التشغيلية.
فئة نموذج Spring ORM
يمكننا استخدام تعليقات JPA القياسية لتعيين التصوير في فئات النموذج لدينا لأن Hibernate يوفر تنفيذ JPA.
package hu.daniel.hari.learn.spring.orm.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Product {
@Id
private Integer id;
private String name;
public Product() {
}
public Product(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + "]";
}
}
نستخدم تعليقات @Entity
و @Id
JPA لتأهيل كائن POJO ككيان ولتعريف مفتاحه الأساسي.
فئة DAO Spring ORM
نقوم بإنشاء فئة DAO بسيطة جدًا توفر طرق persist و findALL.
package hu.daniel.hari.learn.spring.orm.dao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
@Component
public class ProductDao {
@PersistenceContext
private EntityManager em;
public void persist(Product product) {
em.persist(product);
}
public List<Product> findAll() {
return em.createQuery("SELECT p FROM Product p").getResultList();
}
}
- @Component هو تعليق Spring الذي يخبر حاوية Spring أنه يمكننا استخدام هذه الفئة من خلال حقن الاعتماديات في Spring (IoC).
- نستخدم تعليق JPA
@PersistenceContext
للإشارة إلى حقن التبعية في EntityManager. يقوم Spring بحقن نسخة مناسبة من EntityManager وفقًا لتكوين spring.xml.
فئة خدمة Spring ORM
تحتوي فئتنا البسيطة للخدمة على 2 وظيفة للكتابة وواحدة للقراءة – إضافة، إضافة الكل، وقائمة الكل.
package hu.daniel.hari.learn.spring.orm.service;
import hu.daniel.hari.learn.spring.orm.dao.ProductDao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional
public void add(Product product) {
productDao.persist(product);
}
@Transactional
public void addAll(Collection<Product> products) {
for (Product product : products) {
productDao.persist(product);
}
}
@Transactional(readOnly = true)
public List<Product> listAll() {
return productDao.findAll();
}
}
- نستخدم تعليق Spring @Autowired لحقن ProductDao في فئة الخدمة الخاصة بنا.
- نرغب في استخدام إدارة المعاملات، لذا الوسائل محددة بتعليق
@Transactional
من Spring. الوسيلة listAll تقوم فقط بقراءة قاعدة البيانات لذا نحدد تعليق @Transactional كقراءة فقط لتحسين الأداء.
مثال تكوين بيانات Spring ORM
تم إعداد فئات المشروع المثال Spring ORM الخاص بنا، دعنا نلقي نظرة على ملف تكوين بيناتنا bean الخاص بـ spring الآن. spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:p="https://www.springframework.org/schema/p"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:tx="https://www.springframework.org/schema/tx"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
https://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
<context:component-scan base-package="hu.daniel.hari.learn.spring" />
<!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
<context:annotation-config />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem://productDb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="hu.daniel.hari.learn.spring.orm.model"
p:dataSource-ref="dataSource"
>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
- أولاً نخبر Spring أننا نريد استخدام المسح الضوئي لمكونات Spring (الخدمات، DAOs) بدلاً من تعريفها واحدة تلو الأخرى في spring xml. لقد قمنا أيضًا بتمكين كشف التعليقات Spring.
- إضافة مصدر البيانات، وهو قاعدة بيانات HSQLDB في الذاكرة حاليًا.
- قمنا بإعداد JPA
EntityManagerFactory
التي ستُستخدم من قبل التطبيق للحصول على EntityManager. يدعم Spring 3 طرق مختلفة للقيام بذلك، وقد استخدمناLocalContainerEntityManagerFactoryBean
للحصول على جميع إمكانيات JPA. قمنا بتعيين سماتLocalContainerEntityManagerFactoryBean
كالتالي:- سمة packagesToScan التي تشير إلى حزمة فئات النموذج الخاصة بنا.
- مصدر البيانات المعرف سابقًا في ملف تكوين Spring.
- jpaVendorAdapter كـ Hibernate وتعيين بعض خصائص Hibernate.
- نقوم بإنشاء مثيل Spring PlatformTransactionManager كـ JpaTransactionManager. يعتبر هذا المدير مناسبًا لتطبيقات تستخدم JPA EntityManagerFactory واحدة للوصول البيانات التحويلية.
- نمكّن تكوين السلوك التحويلي استنادًا إلى التعليقات، ونقوم بتعيين transactionManager الذي قمنا بإنشائه.
برنامج اختبار مثال Spring ORM Hibernate JPA
مشروع مثالنا Spring ORM JPA Hibernate جاهز، لنكتب برنامج اختبار لتطبيقنا.
public class SpringOrmMain {
public static void main(String[] args) {
//إنشاء سياق تطبيق Spring
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//الحصول على الخدمة من السياق. (تم حقن تبعية الخدمة (ProductDAO) في ProductService)
ProductService productService = ctx.getBean(ProductService.class);
//القيام ببعض العمليات على البيانات
productService.add(new Product(1, "Bulb"));
productService.add(new Product(2, "Dijone mustard"));
System.out.println("listAll: " + productService.listAll());
//اختبار إلغاء المعاملة (مفتاح مكرر)
try {
productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
} catch (DataAccessException dataAccessException) {
}
//اختبار قائمة العناصر بعد التراجع
System.out.println("listAll: " + productService.listAll());
ctx.close();
}
}
يمكنك أن ترى بسهولة كيف يمكننا بدء حاوية Spring من طريقة main. نحصل على نقطة الدخول المحقنة التابعة لدينا الأولى، فصيلة الخدمة. تم حقن مرجع الفئة ProductDao في فئة ProductService بعد تهيئة سياق الربيع. بعد الحصول على مثيل ProducService، يمكننا اختبار طرقه، وستكون جميع استدعاءات الطريقة تراكمية بسبب آلية الوكيل في Spring. نختبر أيضًا التراجع في هذا المثال. إذا قمت بتشغيل برنامج الاختبار أعلاه لمثال ORM الربيع، فستحصل على السجلات أدناه.
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
يرجى ملاحظة أن المعاملة الثانية تم التراجع عنها، وهذا هو السبب في عدم تغيير قائمة المنتجات. إذا استخدمت ملف log4j.properties من المصدر المرفق، يمكنك رؤية ما يحدث تحت الغطاء. المراجع: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html يمكنك تنزيل مشروع مثال Spring ORM JPA Hibernate النهائي من الرابط أدناه واللعب به للتعلم أكثر.
Source:
https://www.digitalocean.com/community/tutorials/spring-orm-example-jpa-hibernate-transaction