في المقالة سوف أصف استخدام Spring Data.
Spring Data عبارة عن آلية ملائمة إضافية للتفاعل مع كيانات قواعد البيانات ، وتنظيمها في مستودع ، واستعادة البيانات ، وتغييرها ، في بعض الحالات ، ستكون كافية لإعلان واجهة وطريقة فيها ، دون تنفيذ.
المحتوى:
- مستودع الربيع
- طلب طرق من اسم الطريقة
- التكوين والإعداد
- معالجة المعلمة الخاصة
- تطبيقات مستودع مخصص
- مستودع قاعدة مخصصة
- طرق الاستعلام - الاستعلام
1. مستودع الربيع
المفهوم الأساسي في Spring Data هو المستودع. هذه هي عدة واجهات تستخدم JPA Entity للتفاعل معها. لذلك على سبيل المثال واجهة
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID>
يوفر عمليات أساسية للبحث عن البيانات وحفظها وحذفها (عمليات CRUD)
T save(T entity); Optional findById(ID primaryKey); void delete(T entity);
وغيرها من العمليات.
هناك تجريدات أخرى ، مثل PagingAndSortingRepository.
أي إذا كانت القائمة التي توفرها الواجهة كافية للتفاعل مع الكيان ، يمكنك بعد ذلك توسيع الواجهة الأساسية لكيانك مباشرةً ، مع استكمالها بطرق الاستعلام الخاصة بك وتنفيذ العمليات. الآن سأعرض بإيجاز تلك الخطوات اللازمة لأبسط الحالات (دون تشتيت حتى الآن من خلال التكوين ، ORM ، قاعدة البيانات).
1. إنشاء كيان
@Entity @Table(name = "EMPLOYEES") public class Employees { private Long employeeId; private String firstName; private String lastName; private String email;
2. موروثة من إحدى واجهات Spring Data ، على سبيل المثال من CrudRepository
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>
3. استخدم في العميل (الخدمة) واجهة جديدة لعمليات البيانات
@Service public class EmployeesDataService { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Transactional public void testEmployeesCrudRepository() { Optional<Employees> employeesOptional = employeesCrudRepository.findById(127L);
أنا هنا استخدمت طريقة
findById الجاهزة . أي بسرعة وسهولة ، دون تنفيذ ، نحصل على قائمة جاهزة من العمليات من CrudRepository:
S save(S var1); Iterable<S> saveAll(Iterable<S> var1); Optional<T> findById(ID var1); boolean existsById(ID var1); Iterable<T> findAll(); Iterable<T> findAllById(Iterable<ID> var1); long count(); void deleteById(ID var1); void delete(T var1); void deleteAll(Iterable<? extends T> var1); void deleteAll();
من الواضح أن هذه القائمة على الأرجح لن تكون كافية للتفاعل مع الكيان ، ويمكنك هنا توسيع الواجهة باستخدام طرق استعلام إضافية.
2. طرق الاستعلام من اسم الأسلوب
يمكن بناء الطلبات إلى الكيان مباشرة من اسم الطريقة. للقيام بذلك ، يتم العثور على ... حسب ، وقراءة ... حسب ، استعلام ... حسب ، العد ... حسب ، والحصول على ... باستخدام البادئات ، بالإضافة إلى بادئة الطريقة ، يبدأ في تحليل باقيها. الجملة التمهيدية قد تحتوي على تعبيرات إضافية ، على سبيل المثال ، مميزة. بعد ذلك ، يعمل الأول حسب الفاصل للإشارة إلى بداية المعايير الفعلية. يمكنك تحديد شروط خصائص الكيان ودمجها باستخدام And و. أمثلة
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> {
تعرّف الوثائق القائمة بأكملها وقواعد كتابة الطريقة. يمكن أن تكون النتيجة كيان T ، اختياري ، قائمة ، دفق. في بيئة التطوير ، مثل Idea ، هناك تلميح لكتابة طرق الاستعلام.

يكفي تحديد طريقة بهذه الطريقة ، دون تنفيذ ، وسيقوم Spring بإعداد طلب للكيان.
@SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testFindByFirstNameAndLastName() { Optional<Employees> employeesOptional = employeesCrudRepository.findByFirstNameAndLastName("Alex", "Ivanov");
3. التكوين والإعداد
المشروع بأكمله متاح على جيثب
github DemoSpringDataهنا سأتطرق فقط إلى بعض الميزات.
يتم تعريف معاملة TransactionManager و dataSource و entityManagerFactory في context.xml. من المهم الإشارة في ذلك أيضًا
<jpa:repositories base-package="com.example.demoSpringData.repositories"/>
المسار حيث يتم تعريف المستودعات.
تم تكوين EntityManagerFactory للعمل مع Hibernate ORM ، وهو بدوره مع قاعدة بيانات Oracle XE ، وهنا توجد خيارات أخرى ممكنة ، في السياق. xml كل هذا مرئي. ملف بوم لديه كل التبعيات.
4. معالجة خاصة من المعلمات
في طرق الاستعلام ، في المعلمات الخاصة بهم ، يمكنك استخدام المعلمات الخاصة Pageable ، Sort ، وكذلك القيود Top and First.
على سبيل المثال ، على هذا النحو ، يمكنك أن تأخذ الصفحة الثانية (الفهرس بـ -0) ، وحجم ثلاثة عناصر وفرزها حسب الاسم الأول ، وبعد تحديد المعلمة Pageable في طريقة المستودع ، سيتم استخدام المعايير من اسم الطريقة - "البحث حسب الاسم الأول يبدأ بـ٪„
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { List<Employees> findByFirstNameStartsWith(String firstNameStartsWith, Pageable page);
5. تطبيقات مخصصة للمستودع
افترض أنك بحاجة إلى طريقة في المخزون لا يمكن وصفها باسم الطريقة ، ثم يمكنك تنفيذها باستخدام الواجهة الخاصة بك وفئة التنفيذ الخاصة بها. في المثال أدناه ، سأضيف إلى المستودع طريقة للحصول على موظفين بأجر أقصى.
تعلن واجهة
public interface CustomizedEmployees<T> { List<T> getEmployeesMaxSalary(); }
تنفذ الواجهة. باستخدام HQL (SQL) أحصل على موظفين بأجر أقصى ، هناك تطبيقات أخرى ممكنة.
public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Override public List getEmployeesMaxSalary() { return em.createQuery("from Employees where salary = (select max(salary) from Employees )", Employees.class) .getResultList(); } }
وأيضًا توسيع مستودعات مستودع Crud مع الموظفين المخصصين.
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees>
هناك ميزة واحدة مهمة هنا. يجب أن تنتهي واجهة تنفيذ الفصل (postfix) على
Impl ، أو في التكوين تحتاج إلى وضع postfix الخاص بك
<repositories base-package="com.repository" repository-impl-postfix="MyPostfix" />
التحقق من تشغيل هذه الطريقة من خلال المستودع
public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testMaxSalaryEmployees() { List<Employees> employees = employeesCrudRepository.getEmployeesMaxSalary(); employees.stream() .forEach(e -> System.out.println(e.getFirstName() + " " + e.getLastName() + " " + e.getSalary())); }
حالة أخرى عندما يكون من الضروري تغيير سلوك طريقة موجودة في واجهة Spring ، على سبيل المثال ، حذف في CrudRepository ، أحتاج أنه بدلاً من الحذف من قاعدة البيانات ، يتم تعيين علامة على الحذف. هذه التقنية هي بالضبط نفس الشيء. أدناه مثال:
public interface CustomizedEmployees<T> { void delete(T entity);
الآن ، إذا قمت بالاتصال
بحذف في staffCrudRepository ، فسيتم تعليم الكائن فقط على أنه محذوف.
6. مستودع قاعدة المستخدم
في المثال السابق ، أوضحت كيفية إعادة تحديد مستودع الحذف لكيان في Crud ، ولكن إذا كنت بحاجة إلى القيام بذلك لجميع كيانات المشروع ، فقم بجعل الواجهة الخاصة بك غير جيدة لكل ... ثم في بيانات Spring ، يمكنك تكوين مستودعك الأساسي. للقيام بذلك:
يتم الإعلان عن واجهة وهي طريقة للتغلب عليها (أو مشتركة بين جميع كيانات المشروع). هنا ، بالنسبة لجميع الكيانات الخاصة بي ، قمت بتقديم واجهة
BaseEntity الخاصة بي (هذا ليس ضروريًا) ، من أجل راحة استدعاء الأساليب الشائعة ، تتوافق أساليبها مع أساليب الكيان.
public interface BaseEntity { Boolean getDeleted(); void setDeleted(Boolean deleted); }
في التكوين ، ستحتاج إلى تحديد مستودع التخزين الأساسي هذا ، وسيكون مشتركًا في جميع مستودعات المشروع
<jpa:repositories base-package="com.example.demoSpringData.repositories" base-class="com.example.demoSpringData.BaseRepositoryImpl"/>
الآن يجب توسيع مستودع الموظفين (وغيرها) من BaseRepository واستخدامه بالفعل في العميل.
public interface EmployeesBaseRepository extends BaseRepository <Employees, Long> {
فحص EmployeesBaseRepository
public class DemoSpringDataApplicationTests { @Resource private EmployeesBaseRepository employeesBaseRepository; @Test @Transactional @Commit public void testBaseRepository() { Employees employees = new Employees(); employees.setLastName("Ivanov");
الآن ، كما كان من قبل ، سيتم تمييز الكائن على أنه محذوف ، وسيتم تنفيذ ذلك لجميع الكيانات التي تعمل على توسيع واجهة BaseRepository. في المثال ، تم تطبيق طريقة البحث -
Query by Example (QBE) ، ولن أصفها هنا ، يوضح المثال ما تقوم به ، بسيط ومريح.
في وقت سابق ، كتبت أنه إذا كنت بحاجة إلى طريقة محددة أو تنفيذها ، والتي لا يمكن وصفها باستخدام اسم الطريقة ، فيمكن القيام بذلك من خلال بعض الواجهات المخصصة (CustomEmployees) وإجراء تطبيق حسابي. ويمكنك الذهاب في الاتجاه الآخر ، من خلال الإشارة إلى الاستعلام (HQL أو SQL) ، وكيفية حساب هذه الوظيفة.
على سبيل المثال الخاص بي مع getEmployeesMaxSalary ، يكون خيار التنفيذ هذا أبسط. أنا سوف تعقيد ذلك مع المعلمة إدخال الراتب. أي يكفي أن تعلن طريقة الحساب والطلب في الواجهة.
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees> { @Query("select e from Employees e where e.salary > :salary") List<Employees> findEmployeesWithMoreThanSalary(@Param("salary") Long salary, Sort sort);
التحقق
@Test @Transactional public void testFindEmployeesWithMoreThanSalary() { List<Employees> employees = employeesCrudRepository.findEmployeesWithMoreThanSalary(10000L, Sort.by("lastName"));
سأشير فقط إلى أنه يمكن أن يكون هناك تعديل الطلبات ، لهذا إضافة تعليق توضيحي إضافي
@ @ لهم
@Modifying @Query("update Employees e set e.firstName = ?1 where e.employeeId = ?2") int setFirstnameFor(String firstName, String employeeId);
تتمثل إحدى الميزات الرائعة
لتعليقات Query في استبدال نوع مجال الكيان في الاستعلام باستخدام القالب
# {# entityName} ، من خلال تعبيرات SpEL.
لذلك ، على سبيل المثال ، في المثال الافتراضي الخاص بي ، عندما أحتاج إلى الحصول على علامة "المحذوفة" لجميع الكيانات ، سأقوم بإنشاء واجهة أساسية مع طريقة للحصول على قائمة الكائنات مع علامة "حذف" أو "نشط"
@NoRepositoryBean public interface ParentEntityRepository<T> extends Repository<T, Long> { @Query("select t from #{#entityName} t where t.deleted = ?1") List<T> findMarked(Boolean deleted); }
علاوة على ذلك ، يمكن تمديد جميع مستودعات الكيانات منه. واجهات غير مستودعات ، ولكن تقع في مجلد التكوين "الحزمة الأساسية" ، علقNoRepositoryBean.
مستودع الموظفين
@Repository public interface EmployeesEntityRepository extends ParentEntityRepository <Employees> { }
الآن عند تنفيذ الطلب ، سيتم استبدال اسم الكيان
T في نص الطلب لمستودع محدد يمتد ParentEntityRepository ، في هذه الحالة الموظفون.
تحقق
@SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private EmployeesEntityRepository employeesEntityRepository; @Test @Transactional public void testEntityName() { List<Employees> employeesMarked = employeesEntityRepository.findMarked(true);
المواد
بيانات الربيع JPA - الوثائق المرجعيةمشروع على جيثب .