أفضل ممارسات ترميز Java لإعادة استخدام جزء من الاستعلام لحساب العدد

StackOverflow https://stackoverflow.com/questions/1600440

سؤال

ال تنفيذ نتيجة الترحيل في السبات والحصول على إجمالي عدد الصفوف سؤال يثير سؤالا آخر بالنسبة لي، حول بعض المخاوف بشأن التنفيذ:

الآن أنت تعلم أنه يتعين عليك إعادة استخدام جزء من استعلام HQL لإجراء العد، فكيف يمكن إعادة استخدامه بكفاءة؟

الاختلافات بين استعلامات HQL هي:

  1. الاختيار هو count(?), ، بدلاً من pojo أو الخاصية (أو قائمة)
  2. لا ينبغي أن تحدث عمليات الجلب، لذا لا ينبغي ضم بعض الجداول
  3. ال order by يجب أن تختفي

هل هناك اختلافات أخرى؟

هل تمتلك ترميز أفضل الممارسات لتحقيق إعادة الاستخدام بكفاءة (مخاوف:الجهد والوضوح والأداء)؟

مثال لاستعلام HQL بسيط:

    select       a     from A a join fetch a.b b where a.id=66 order by a.name
    select count(a.id) from A a                  where a.id=66

محدث

وصلتني الإجابات على:

  • استخدام معايير (لكننا نستخدم HQL في الغالب)
  • التلاعب بالسلسلة الاستعلام (لكن الجميع متفقون على أنه يبدو معقدًا وغير آمن جدًا)
  • التفاف الاستعلام, ، الاعتماد على تحسين قاعدة البيانات (ولكن هناك شعور بأن هذا ليس آمنًا)

كنت آمل أن يقدم شخص ما خيارات على طول مسار آخر، أكثر ارتباطًا بتسلسل السلسلة.
هل يمكننا بناء استعلامات HQL باستخدام الأجزاء المشتركة?

هل كانت مفيدة؟

المحلول

سؤال جيد.إليك ما قمت به في الماضي (العديد من الأشياء التي ذكرتها بالفعل):

  1. تحقق مما إذا كان يختار الشرط موجود.
    1. إذا لم يكن كذلك، أضف select count(*)
    2. خلاف ذلك تحقق ما إذا كان لديه متميز أو الوظائف المجمعة فيه.إذا كنت تستخدم ANTLR لتحليل استعلامك، فمن الممكن التغلب على هذه المشكلات ولكنها معنية تمامًا.من الأفضل أن تقوم بتغليف كل شيء به select count(*) from ().
  2. يزيل fetch all properties
  3. يزيل fetch من الصلات إذا كنت تقوم بتحليل HQL كسلسلة.إذا كنت تقوم حقًا بتحليل الاستعلام باستخدام ANTLR، فيمكنك إزالته left join تماما؛إنه أمر فوضوي إلى حد ما للتحقق من جميع المراجع الممكنة.
  4. يزيل order by
  5. اعتمادًا على ما قمت به في الإصدار 1.2، ستحتاج إلى الإزالة/التعديل group by / having.

ما ورد أعلاه ينطبق على HQL، بطبيعة الحال.بالنسبة لاستعلامات المعايير، فأنت محدود تمامًا بما يمكنك فعله لأنه لا يمكن التلاعب به بسهولة.إذا كنت تستخدم نوعًا ما من طبقة التغليف أعلى المعايير، فسوف ينتهي بك الأمر بمجموعة فرعية مكافئة (محدودة) من نتائج تحليل ANTLR ويمكنك تطبيق معظم ما سبق في هذه الحالة.

نظرًا لأنك عادةً ما تتمسك بإزاحة صفحتك الحالية والعدد الإجمالي، عادةً ما أقوم بتشغيل الاستعلام الفعلي بحد/إزاحة معين أولاً وأقوم فقط بتشغيل count(*) استعلام إذا كان عدد النتائج التي يتم إرجاعها أكبر أو يساوي الحد والإزاحة صفر (في جميع الحالات الأخرى، قمت إما بتشغيل الأمر count(*) من قبل أو حصلت على جميع النتائج مرة أخرى على أي حال).وهذا نهج متفائل فيما يتعلق بالتعديلات المتزامنة بالطبع.

تحديث (على تجميع HQL يدويًا)

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

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

لقد فعلت فعلا فكرت قليلا جدا بشأن هذه المسألة.بحث API من السبات-عام-DAO يبدو وكأنه حل وسط معقول.هناك المزيد من التفاصيل في إجابتي على السؤال المرتبط أعلاه.

نصائح أخرى

هل حاولت توضيح نواياك للإسبات من خلال تعيين إسقاط على معايير (SQL؟) الخاصة بك؟لقد كنت أستخدم المعايير في الغالب، لذا لست متأكدًا من مدى قابلية تطبيق ذلك على حالتك، لكنني كنت أستخدمها

getSession().createCriteria(persistentClass).
setProjection(Projections.rowCount()).uniqueResult()

والسماح لـ Hibernate باكتشاف التخزين المؤقت/إعادة الاستخدام/الأشياء الذكية بنفسه..لست متأكدًا حقًا من مقدار الأشياء الذكية التي تفعلها بالفعل.أي شخص يهتم بالتعليق على هذا؟

حسنًا، لست متأكدًا من أن هذه هي أفضل ممارسة، ولكنها ممارستي :)

إذا كان لدي استعلام شيء مثل:

select A.f1,A.f2,A.f3 from A, B where A.f2=B.f2 order by A.f1, B.f3

وأريد فقط أن أعرف عدد النتائج التي سأحصل عليها، أقوم بتنفيذ:

select count(*) from ( select A.f1, ... order by A.f1, B.f3 )

ثم احصل على النتيجة كعدد صحيح، دون تعيين النتائج في POJO.

إن تحليل استعلامك لإزالة بعض الأجزاء، مثل "الترتيب حسب" أمر معقد للغاية.سيعمل نظام RDBMS الجيد على تحسين استعلامك نيابةً عنك.

سؤال جيد.

في حالة HQL اليدوية، سأستخدم شيئًا مثل هذا ولكن هذا غير قابل لإعادة الاستخدام لأنه محدد تمامًا للكيانات المحددة

Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

افعل ذلك مرة واحدة واضبط رقم البداية وفقًا لذلك حتى تنتهي من الصفحة.

بالنسبة للمعايير على الرغم من أنني أستخدم عينة مثل هذه

final Criteria criteria = session.createCriteria(clazz);  
            List<Criterion> restrictions = factory.assemble(command.getFilter());
            for (Criterion restriction : restrictions)
                criteria.add(restriction);
            criteria.add(Restrictions.conjunction());
            if(this.projections != null)
                criteria.setProjection(factory.loadProjections(this.projections));
            criteria.addOrder(command.getDir().equals("ASC")?Order.asc(command.getSort()):Order.desc(command.getSort()));
            ScrollableResults scrollable = criteria.scroll(ScrollMode.SCROLL_INSENSITIVE);
            if(scrollable.last()){//returns true if there is a resultset
                genericDTO.setTotalCount(scrollable.getRowNumber() + 1);
                criteria.setFirstResult(command.getStart())
                        .setMaxResults(command.getLimit());
                genericDTO.setLineItems(Collections.unmodifiableList(criteria.list()));
            }
            scrollable.close();
            return genericDTO;

ولكن هذا لا يحسب في كل مرة عن طريق الاتصال ScrollableResults:last().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top