محتويات الدورة

Spring Boot / المتوسط: البيانات والأمان وأدلة الإطار / الدرس 7

مستودعات JPA وسياق الاستمرارية

نمذج حد الاستمرارية بهوية كيان وثوابت قاعدة واستعلام مقيد وصفحات وكشف DTO مضبوط.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • تمييز حالة الكيان من نموذج الرد العام.
  • شرح save و flush والتثبيت وفحص النسخة.
  • تقييد نطاق المستودع وحجمه.

المستودع قدرة تعتمد عقد تخزين فعلياً

توفر Spring Data آلية تنفيذ المستودع حول JPA، وقد تضبط Boot البنية من الاعتماد والإعداد. لا يستنتج أيهما مخطط مجال صحيحاً؛ فاختر الهوية والمطلوب والتفرد والعلاقات ومالك الترحيل. لا تعتمد بيانات الإنتاج إعادة إنشاء صامتة عند كل بدء.

الكيان حالة مُدارة لا DTO عامة مستقرة تلقائياً. تختلف هويته ومساواته وعمره وعلاقاته الكسولة من اختيار الحقول. وتحمي قيود القاعدة التزامن خارج المتحكم. اختبر اللهجة والموفر الفعليين؛ ولا تستخدم الدورة قاعدة مهيأة أو تعدل مخططها تلقائياً لإثبات المثال.

صرح بالهوية والنطاق والنسخة المتفائلة

يستخدم الجزء Jakarta لأساس 3.5، وبانياً بلا معاملات محمياً لإنشاء JPA، وهوية Long يدعم توليدها الموفر، و Version لفحص التحديث المتفائل. تصف قاعدة المستأجر والرمز ثابتاً مطلوباً؛ لكن يجب أن تنشئه ترحيلات مراجعة في المخطط الفعلي، لا افتراض أن annotation غيرت الإنتاج.

ليس تعارض النسخة إذناً بكتابة غير مشروطة مكررة؛ أعد القراءة أوصالح مع حفظ عمل الآخر. قيد البحث والتعديل بالنطاق الموثوق. لا يفوض اسم tenantId المستدعي، وقد يحتاج ناتج findById فحص ملكية قبل كشفه حتى مع نجاح الاستعلام.

java هوية كيان وثابت مستأجر ورمز توضيحيان
package training.catalog;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import jakarta.persistence.Version;

@Entity
@Table(name="catalog_product", uniqueConstraints=@UniqueConstraint(
    name="uk_product_tenant_code", columnNames={"tenant_id","code"}))
class Product {
    @Id @GeneratedValue private Long id;
    @Version private Long version;
    @Column(name="tenant_id", nullable=false) private String tenantId;
    @Column(nullable=false) private String code;
    @Column(nullable=false) private int unitPriceCents;
    protected Product() {}
}

التوليد والترحيل ودوال المجال وتنفيذ الموفر سياقية؛ ولا ينشئ الجزء قاعدة.

اختر تمثيلاً محدوداً ضمن نطاق موثوق

يطلب الجزء صفحة إسقاط مغلق لا شبكة كيان كاملة. يجب اشتقاق المستأجر من نطاق موثوق وتقييد حجم الصفحة وترتيبها بمعرف فريد مثلاً. قد يشتق الاسم استعلاماً، لكن SQL والفهرس والسلوك الفعلي تحتاج دليلاً تكاملياً.

توفر Page معلومات إجمالي وقد تحتاج عدّاً إضافياً. قد تناسب Slice أوالمتابعة بالمفتاح منتجاً يحتاج التالي فقط، ولكل عقد اتساق وترتيب. لا تكشف findAll بلا حد لصغر بيانات التدريب. وقد تزيح التغييرات الصفحات إذا لم يتحكم تصميم الاستخراج فيها.

java إسقاط صفحة مقيدة توضيحي
package training.catalog;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

interface ProductSummary {
    Long getId();
    String getCode();
    int getUnitPriceCents();
}

interface ProductRepository extends JpaRepository<Product, Long> {
    Page<ProductSummary> findByTenantId(String tenantId, Pageable pageable);
}

يلزم نطاق موثوق و Pageable محدودة مرتبة؛ ولم ينفذ SQL للمستودع.

افصل التغير المُدار و flush والدوام

يتتبع سياق الاستمرارية الكيان المُدار وقد يرسل تغيره بالفحص المتسخ. تختار save الحفظ أوالدمج بحسب الحالة ولا تضمن إدراجاً فورياً أو دواماً مستقلاً. تزامن flush العمل المعلق مع القاعدة داخل المعاملة، ويكمل commit تثبيتها وفق النتيجة؛ وقد يظهر الفشل عندهما لا عند تعديل الحقل.

قد يفشل الوصول الكسول خارج السياق أو يسبب عملاً خفياً وفق الضبط. لا تجعل كل علاقة eager ولا تفتح قراءات أثناء التسلسل كعلاج عام. حدد بيانات الحالة واجلبها بقصد وحول نتيجة معتمدة داخل حد قراءة واضح.

اختبر حد القاعدة مستقلاً عن البديل

تحقق من الربط والترحيل والقيود والنطاق والترتيب وتعارض النسخة بقاعدة مقصودة معزولة عند السماح. لا يثبت mock SQL المولد أوالتفرد، ولا تعيد قاعدة ذاكرية بلهجة أخرى أقفال النشر وأنواعه وخططه تلقائياً.

أبق البيانات مصطنعة ولا توجه DataJpaTest إلى مصدر المشروع عرضاً. لا تجهز خدمة هنا وتبقى الأجزاء غير قابلة للتشغيل. يحدد المستودع الصحيح المخزن ونطاق المستدعي وعمر الإدارة والدليل على الاستمرارية الفعلية، لا مجرد صحة استدعاء دالة بديلة.

الأخطاء الشائعة وإصلاحها

LazyInitializationException

لماذا يحدث؟
قُرئت حالة كسولة خارج سياقها.
كيف تصلحه؟
اجلب وحول المطلوب وراجع حد القراءة.
كيف تتجنب تكراره؟
اختبر التحويل وعد الطلبات.

OptimisticLockException

لماذا يحدث؟
تعارض تحديث نسخة مع كاتب آخر.
كيف تصلحه؟
صالح أوارفض وفق السياسة.
كيف تتجنب تكراره؟
اختبر تحريراً متزامناً بدلالة النسخة.

سمي mock تغطية SQL.

لماذا يحدث؟
لم ينفذ موفر أو استعلام.
كيف تصلحه؟
أضف دليلاً معزولاً للهجة عند السماح.
كيف تتجنب تكراره؟
ميز مستويات الاختبار.

اختبر فهمك

1. هل تثبت save دوام الطلب؟

اعرض الحل المشروح

لا؛ قد تؤجل SQL أوتفشل عند flush أو commit. على المالك ملاحظة الإكمال، وعلى المستدعي تمييز المؤكد من فقد الرد.

2. لماذا يفيد الإسقاط ولا يكفي وحده؟

اعرض الحل المشروح

يقلل الحقول ويحدد الصفحة، لكنه يحتاج نطاقاً وحجماً وترتيباً وكلفة عد وفحص لهجة. ليس تفويضاً أوضمان سرعة مجانياً.

أهم ما تعلمته

  • تختلف حياة الكيان من تمثيل الرد.
  • save و flush و commit أحداث مختلفة.
  • يحتاج المستودع دليلاً لحد التخزين الفعلي.

المراجع الرسمية