الجميع هنا على حق ، كل في طريقته الخاصة ، وبالتالي الجميع هنا على خطأ.
"حكاية الثلاثة" (A. و B. Strugatsky)
إذا كنت تستخدم Spring Data JPA ، ثم بعد الترقية إلى Spring Boot 2 ، عند بدء تشغيل التطبيق ، قد تلاحظ تحذيرًا جديدًا في السجل:
يتم تمكين spring.jpa.open-in-view افتراضيًا. لذلك ، قد يتم تنفيذ استعلامات قاعدة البيانات أثناء تقديم العرض. صراحة تكوين spring.jpa.open في طريقة العرض لتعطيل هذا التحذير.
سأحاول في هذه المقالة شرح معنى ذلك ، من يقع اللوم وماذا يفعل.
لرفع تطبيق كامل على Spring Boot ، لا @SpringBootApplication
سوى تعليق توضيحي واحد @SpringBootApplication
. لجعل هذا ممكنًا ، يستخدم الإطار عددًا كبيرًا من التكوينات التلقائية والإعدادات الافتراضية. علاوة على ذلك ، للعمل خارج الصندوق ، كان على مطوري Spring Boot اختيار بعض مفاهيم تطوير التطبيق من عدة خيارات بديلة لكل منهم ، بحيث لا يحتاج المستخدم إلى تحديدها بشكل صريح. من ناحية ، يعد هذا أمرًا جيدًا لبداية سريعة وتطوير سهل ، ولكن من ناحية أخرى ، قد يتضح بعد بعض الوقت أن بعض المفاهيم / النماذج / الإعدادات الافتراضية غير مناسبة للمشروع ، وسوف يتعين القيام بالكثير من العمل للتخلي عنه. أحد هذه المفاهيم هو وضع الجلسة المفتوحة في طريقة العرض (OSIV) ، والذي يتم تضمينه افتراضيًا في Spring Boot.
في هذا الوضع ، تظل جلسة الإسبات مفتوحة طوال الوقت الذي تتم فيه معالجة طلب HTTP ، بما في ذلك مرحلة إنشاء طريقة العرض (مورد JSON أو صفحة HTML). هذا يجعل من الممكن تحميل البيانات بتكاسل في طبقة العرض التقديمي بعد تنفيذ معاملة في طبقة منطق الأعمال. على سبيل المثال ، نطلب كيان Article
من قاعدة البيانات. يجب أن يتم عرض المقالة مع التعليقات. يتيح لك OSIV ببساطة استدعاء طريقة الكيان getComments()
عند تقديم HTML ، وسيتم تحميل التعليقات في طلب منفصل. عند تعطيل وضع OSIV ، سنحصل على LazyInitializationException
، لأن الجلسة مغلقة بالفعل ولم يعد كيان Article
يديرها السبات. واجه معظم مطوري الإسبات LazyInitializationException
؛ يتيح لك OSIV تجنبه عن طريق تحميل البيانات حسب الضرورة في أي مرحلة من مراحل معالجة طلب HTTP.
يتم تطبيق OSIV في Spring Boot باستخدام OpenEntityManagerInViewInterceptor
طلب الويب OpenEntityManagerInViewInterceptor
. على عكس الربيع النقي ، يتم تمكينه افتراضيًا.
OSIV يعتبر antipattern. أفضل ما في الأمر هو أن الجانب الضار من مقاله قد أوضحه فلاد ميهالسيا ، أحد مطوري هيبيرنيت: الجلسة المفتوحة في طريقة العرض المضادة للأنماط . النقاط الرئيسية:
- تعمل استعلامات قاعدة البيانات بدون معاملة في وضع الالتزام التلقائي ، وتحميلها بشدة.
- لا يوجد فصل للمسؤوليات ، يمكن لأي طبقة تطبيق إنشاء استعلامات SQL ، مما يجعل الاختبار صعبًا.
- هناك مشكلة في n + 1 عند تحميل كل مجموعة مرتبطة بكيان في طلب منفصل.
- اتصالات طويلة إلى قاعدة البيانات مرة أخرى زيادة الحمل على ذلك وتقليل الإنتاجية.
هذه مشكلات غير سارة تمامًا في وضع OSIV ، ويبدو أن هناك حجج قوية لعدم استخدامها. ومع ذلك ، في طلب لتعطيله افتراضيًا ، قدم مطورو Spring Boot أيضًا أسبابًا وجيهة وراء تمكين OSIV للمشاريع الجديدة:
- التوافق الخلفي. قد تواجه التطبيقات الحالية عند الترقية إلى Spring Boot 2 الأخطاء والأخطاء بسبب تعطيل OSIV. لتجنب ذلك ، ما عليك سوى تعيين
spring.jpa.open-in-view
القيمة spring.jpa.open-in-view
، ولكن هذا يجعل أيضًا من الصعب التبديل إلى الإصدار الجديد. - سهولة الاستخدام للمبتدئين وبداية سريعة مهمة لـ Spring Boot. إذا تم تعطيل OSIV ، فقد لا يكون من الواضح للمبتدئين لماذا لا يعمل شيء متوقع بشكل حدسي مثل تلقي مجموعة من العناصر ذات الصلة عند الوصول إلى طريقة الكيان. بدلاً من ذلك ، سيتلقى المستخدم
LazyInitializationException
، سيؤدي ذلك إلى إبطاء طريقه إلى تطبيق قيد التشغيل. - يتيح لك OSIV زيادة بساطة الرمز وسهولة الاستخدام وسرعة التطوير.
- من الصعب العثور على أمثلة بسيطة عن كيفية إنشاء تطبيق بدون OSIV.
- بدون OSIV ، تحتاج طبقة منطق العمل إلى معرفة كيفية تقديم البيانات في واجهة المستخدم ، أي ما تحتاجه DTO أو البيانات ذات الصلة التي ينبغي تحميلها مع الكيان الجذر. هذا هو مرة أخرى عدم وجود تقسيم للمسؤولية.
لذلك ، يمكننا التمييز بين اثنين من وجهات النظر حول هذه المشكلة. من وجهة نظر مهندس قاعدة البيانات (DBA) ، من المؤكد أن فتح الجلسة في العرض غير مقبول ، لأن تفاعل التطبيق مع قاعدة البيانات غير منظم على النحو الأمثل ويتسبب في زيادة الحمل. لكننا نستخدم غالبًا حلولًا أقل مثالية للسرعة وسهولة التطوير وأدوات التعلم - نكتب بلغات مدارة ونستخدم تنسيقات البيانات النصية للتفاعل في الشبكة وما إلى ذلك. من موقع مطور الإطار ، لتبسيط التطوير والبدء السريع للمبتدئين ، يتيح لك OSIV تقليل الحمل المعرفي ، وعدد المفاهيم اللازمة لبدء تطوير التطبيق. إذا اختار المطور JPA ، فقد وافق بالفعل على بعض تدهور الأداء في مقابل راحة التطوير. يساعد JPA في تكوين صداقات الكائن ونماذج البيانات العلائقية. عند العمل على نمط الكائن للحصول على العناصر ذات الصلة ، ننتقل ببساطة إلى طريقة الكيان (حتى لو كانت في طبقة العرض التقديمي) ، فهي بسيطة ومنطقية ومتوقعة بشكل حدسي ، على الرغم من أن هذه البساطة مخادعة.
هناك العديد من الأمثلة والبرامج التعليمية للعمل في وضع الجلسة المفتوحة في طريقة العرض ، فإن البنية ككل واضحة: تطلب طبقة الخدمة كيان JPA ، أو طبقة العرض التقديمي تسلسلها في JSON مباشرة ، من خلال DTO وسيط ، أو تستخدم البيانات منه لتقديم صفحة HTML.
أقل وضوحا هو كيفية العمل دون OSIV. أحد مطوري Spring في الطلب المذكور يشكو من ذلك ، يقولون الكثير من الصراخ حول المضاد ، لكن لا توجد أمثلة بسيطة عن كيفية العيش بدونه. في هذا النموذج ، يمكن استخدام الكيانات فقط للكتابة ، وللقراءة ، DTOs متعددة ، منفصلة لكل مجموعة بيانات في واجهة المستخدم ، والتي يتم تعيينها مباشرة من قاعدة البيانات. أو استعلامات SQL مخصصة تصف صلة المجموعات ذات الصلة الضرورية لاستعلام ويب معين. هذا هو ، المزيد من القواعد المعيارية ووصف لاحتياجات واجهة المستخدم في طبقة منطق الأعمال. مع تعطيل OSIV ، يبدأ تدفق JPA في التدفق ، ويصف التطبيق مزيدًا من التفاصيل الفنية للتفاعل مع قاعدة البيانات.
وبالتالي ، فإن التطوير مع OSIV أبسط. ولكن المشكلة هي أنه إذا كنت ترغب في التخلي عنها في المستقبل ، فسيتعين عليك إعادة الكثير ، لا يمكن تغيير مفهوم العمل مع قاعدة البيانات في المشروع عن طريق تعيين خاصية واحدة. قد تحتاج إلى إعادة بنية التطبيق بالكامل. ومع ذلك ، قد يكون التخلي عن OSIV بمثابة تحسين سابق لأوانه ، مما سيؤدي إلى إبطاء سرعة التطوير ، والتي قد تكون حاسمة لبدء التشغيل ، على سبيل المثال. يمكنك استخدام OSIV وتحسين استعلامات قاعدة البيانات فقط في أبطأ الأماكن. على سبيل المثال ، يكون الاستعلام عن مجموعات الكيانات أكثر معاناة من المشكلة n + 1 ، عندما يسحب كل كيان العديد من الاستعلامات من المجموعات ذات الصلة.
لذلك ، إذا كنت ترغب في القيام بذلك بشكل صحيح ، فأنت بحاجة إلى تطوير بدون OSIV. ولكن إذا كانت سرعة التطوير وبساطة الرمز مهمة ، فيمكنك استخدام هذا الوضع ، واستسلم لبعض الخسارة في الأداء.
الشيء الرئيسي هو أن مشكلة الأداء هذه لا تتحول إلى ديون فنية ضخمة بعد بضع سنوات. يكون الأمر خطيرًا مضاعفًا عندما لا يشك المطورون في أن هذا الدين يتراكم لديهم ، لأن Spring Boot اختار بصمت مفهوم Open Session In View لهم. لذلك ، من الجيد أنه نتيجة للطلب المذكور أعلاه ، فقد تقرر أن يعرض في السجل تحذيرًا بشأن الوضع المستخدم ، والذي نقلت عنه في بداية المقال.
آمل أن يساعد هذا التحذير وهذا المقال عنه المطورين على اتخاذ قرار أكثر استنارة - ما إذا كان سيتم استخدام مفهوم Open Session In View في تطبيق على Spring Boot. لقد استشهدت وناقشت الحجج الرئيسية المؤيدة والمعارضة ، وأوصي أيضًا بقراءة المناقشة الأصلية. توضح هذه المشكلة أن عددًا كبيرًا من التكوينات التلقائية والإعدادات الافتراضية في برنامج Spring / Spring Boot يمكن أن يكون خطيرًا على المطورين غير المهتمين.
هل تستخدم OSIV في تطبيقات Spring Boot؟ إذا لم يكن الأمر كذلك ، فكيف يتم تنظيم بنية تفاعل طبقة العرض التقديمي مع قاعدة البيانات؟ ما التقنيات و / أو المكتبات المستخدمة لهذا؟