java - لماذا أحتاج إلى معاملة في إسبات للقراءة فقط للعملية؟




database hibernate (3)

في الواقع ، تضع المعاملات أقفال في قاعدة البيانات - حيث تتعامل محركات قواعد البيانات الجيدة مع الأقفال المتزامنة بطريقة معقولة - وهي مفيدة في الاستخدام للقراءة فقط لضمان عدم قيام أي معاملة أخرى بإضافة بيانات تجعل المشاهدة غير متناسقة. أنت دائمًا تريد إجراء معاملة (على الرغم من أنه من المعقول أحيانًا ضبط مستوى العزلة ، فمن الأفضل عدم القيام بذلك للبدء) ؛ إذا لم تكتب أبداً إلى DB أثناء المعاملة الخاصة بك ، فكل من يرتكب ويعيد تنفيذ المعاملة إلى أن يكون هو نفسه (ورخيص جداً).

الآن ، إذا كنت محظوظًا وكانت استعلاماتك على قاعدة بيانات DB هي التي يحددها ORM دائمًا لاستعلامات SQL الفردية ، فيمكنك الابتعاد دون إجراء معاملات صريحة ، بالاعتماد على سلوك autocommit المدمج في DB ، ولكن ORMs هي أنظمة معقدة نسبيًا لذلك ليس من الآمن الاعتماد على مثل هذا السلوك إلا إذا ذهبت إلى الكثير من العمل للتحقق مما يقوم به التطبيق بالفعل. إن كتابة حدود المعاملة الصريحة أسهل بكثير (خاصة إذا كان بإمكانك القيام بذلك باستخدام AOP أو بعض التقنيات المشابهة التي تعتمد على ORM ؛ فمن Java 7 فصاعداً يمكن استخدام المحاولة باستخدام الموارد أيضًا).

لماذا أحتاج إلى معاملة في إسبات للقراءة فقط للعملية؟
هل الصفقة التالية تضع قفل على ديسيبل؟

رمز المثال لجلب من db:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything


هل يمكنني استخدام session.close() بدلاً من tx.commit() ؟؟


قد يكون لديك بالفعل أسباب لتمييز المعاملات على أنها للقراءة فقط.

  1. قد تبدو معاملات القراءة غريبة بالفعل وغالباً لا يضع الأشخاص علامات على المعاملات في هذه الحالة. ولكن JDBC ستنشئ معاملة على أي حال ، إنها فقط ستعمل في autocommit=true إذا لم يتم ضبط خيار مختلف بشكل صريح.
  2. ولكن لا يوجد أي ضمان بأن أسلوبك لا يكتب في قاعدة البيانات. إذا قمت بتمييز الطريقة كـ @Transactional(readonly=true) ، فسيقوم Spring بتعيين معاملة JDBC في وضع القراءة فقط ، وبالتالي ستقوم بإملاء ما إذا كان من الممكن بالفعل الكتابة إلى DB في نطاق هذه المعاملة. إذا كانت الهندسة المعمارية مرهقة للغاية وقد لا يتبع بعض أعضاء الفريق مسارًا معقولًا ، فإن هذا العلم سيوجهك إلى مكان الإشكالية.
  3. يمكن أيضًا تحسين المعاملات المقروءة فقط بواسطة DBs ، ولكن هذا بالطبع هو DB محدد. أضاف Eg MySQL دعمًا لهذا فقط في InnoDB بدءًا من إصدار 5.6.4.
  4. إذا كنت لا تستخدم JDBC مباشرة ، ولكن بالأحرى ORM ، فقد يكون ذلك مشكلة. على سبيل المثال ، يقول مجتمع Hibernate أن العمل خارج نطاق المعاملة قد يسبب سلوكًا غير متوقع. وذلك لأن السبات سيفتح المعاملة ، ولكنه لن يغلقه من تلقاء نفسه ، وبالتالي سيتم إرجاع الاتصال إلى "تجمع الاتصالات" مع معاملة غير ملتزم بها. ما يحدث بعد ذلك؟ يبقى JDBC صامتا ، وبالتالي هذا هو تنفيذ معين (تتراجع MySQL المعاملة ، أوراكل أفاير يرتكبها). يمكن تكوين هذا أيضًا على مستوى تجمّع الاتصال (على سبيل المثال ، تعطيك C3P0 مثل هذا الخيار ، التراجع عن الوضع الافتراضي).
  5. شيء آخر عندما يتعلق الأمر بـ Hibernate ، يقوم Spring بتعيين FlushMode إلى MANUAL في حالة المعاملات التي يتم إجراؤها للقراءة فقط ، مما يؤدي إلى تحسينات أخرى مثل عدم الحاجة إلى عمليات فحص متسخة.
  6. قد ترغب في تجاوز مستوى عزل المعاملة أو تعيينه بشكل صريح. يؤثر ذلك على المعاملات المقروءة أيضًا لأنك تريد أو لا ترغب في قراءة التغييرات غير الملتزم بها ، أو تعرضها لقراءات وهمية ، إلخ.

لتلخيص - يمكنك الذهاب في كلا الاتجاهين ، ولكن عليك أن تفهم العواقب.


يتم تنفيذ جميع بيانات قاعدة البيانات في سياق المعاملات الفعلية ، حتى عندما لا نعلن بوضوح حدود المعاملة (BEGIN / COMMIT / ROLLBACK).

إذا لم تقم بإعلان حدود المعاملة بشكل صريح ، فسيتم تنفيذ كل عبارة في معاملة منفصلة (وضع autocommit ). وقد يؤدي ذلك إلى فتح وإغلاق اتصال واحد لكل بيان ما لم تتمكن بيئتك من التعامل مع ربط مؤشر الترابط لكل اتصال.

إن الإعلان عن خدمة باسم @Transactional سيمنحك اتصالاً واحدًا لمدة المعاملة بالكامل ، وستستخدم جميع العبارات اتصال العزل الوحيد هذا. هذا أفضل من عدم استخدام المعاملات الصريحة في المقام الأول.

في التطبيقات الكبيرة ، قد يكون لديك العديد من الطلبات المتزامنة ، وسيعمل تقليل معدل طلب الحصول على اتصال قاعدة البيانات على تحسين أداء التطبيقات بشكل عام.

JPA لا تفرض المعاملات على عمليات القراءة. تنتهي عمليات الكتابة فقط برمي استثناء المعاملة المطلوب في حالة نسيان بدء سياق معاملات. ومع ذلك ، فمن الأفضل دائمًا إعلان حدود المعاملة حتى بالنسبة للمعاملات المقروءة فقط (في @Transactional يسمح لك بوضع علامة على المعاملات للقراءة فقط ، والتي تتمتع بأداء رائع).





database-connection