يوفر MyBatis وظائف استعلام Advanced Association ، والتي يمكنها بسهولة تعيين مجموعات النتائج التي تم الحصول عليها بواسطة قاعدة البيانات إلى حبوب Java المحددة. فيما يلي مثالًا لإظهار كيف يتعامل MyBatis مع تعيينات علاقات معقدة من شخص واحد إلى واحد إلى واحد.
صمم نظام مدونة بسيط حيث يمكن للمستخدم فتح مدونات متعددة ، ونشر المقالات في المدونة ، والسماح بالتعليقات ، ومقالات العلامات. يتكون نظام المدونة بشكل أساسي من الجداول التالية:
جدول المؤلف: جدول معلومات المؤلف ، سجل معلومات المؤلف ، اسم المستخدم وكلمة المرور ، عنوان البريد الإلكتروني ، إلخ.
جدول المدونة: جدول المدونة ، يمكن للمؤلف فتح مدونات متعددة ، أي أن العلاقة بين المؤلف والمدونة هي واحدة إلى أقراص.
جدول النشر: جدول سجل المقالة ، تسجيل وقت النشر ، العنوان ، النص والمعلومات الأخرى ؛ يمكن أن يكون هناك العديد من المقالات تحت مدونة ، والعلاقة بين المدونة والنشر هي واحدة إلى أقصى.
تعليقات التعليقات: جدول تعليق المقال ، تسجيلات السجل ، يمكن أن يكون للمقال العديد من التعليقات: المراسلات بين Post and Explys هي واحدة إلى العمال.
جدول العلامات: جدول العلامة ، والذي يمثل تصنيف العلامات للمقال. يمكن أن تحتوي المقالة على علامات متعددة ، ويمكن تطبيق علامة على مقالات مختلفة ، وبالتالي فإن العلاقة بين العلامة والنشر هي علاقة عديدة ؛ (تنعكس العلاقة بين العديد من الأشياء بين العلامة والنشر من خلال جدول post_tag)
جدول post_tag: يسجل المراسلات بين المقالات والعلامات.
بشكل عام ، سنقوم بإنشاء جافابان (أو POJO) المقابل بناءً على بنية كل جدول لإكمال عملية CRUD الأساسية للجدول.
لا يمكن في بعض الأحيان بتعريف جافابان لجدول واحد في بعض الأحيان تلبية احتياجات العمل. في الأعمال التجارية ، يجب أن يحتوي كائن المدونة على معلومات حول مؤلفها وقائمة المقالات ، كما هو موضح في الشكل أدناه:
إذا كنت ترغب في الحصول على مثيل لمثل هذا الفصل ، فأنت بحاجة إلى بضع خطوات على الأقل:
1. الاستعلام عن معلومات المدونة من خلال معرف المدونة في جدول المدونة ، وقم بتعيين مدونة الاستعلام وعنوان كائن المدونة ؛
2. وفقًا لـ The Query AuthorId في معلومات المدونة ، انتقل إلى جدول المؤلف للحصول على معلومات المؤلف المقابلة ، والحصول على كائن المؤلف ، ثم تعيينه إلى كائن المدونة ؛
3. وفقًا لـ BlogId ، استعد قائمة مقالات النشر المقابلة في جدول النشر وتعيين الكائن <post> إلى كائن المدونة ؛
وبهذه الطريقة ، يتم استدعاء ثلاثة عبارات استعلام على الأقل في الطبقة السفلية. يرجى الاطلاع على الرمز التالي:
/** احصل على كائن bloginfo من خلال blogid*/ public static bloginfo multiciCqueryOntest (String blogid) {BigDecimal id = new BigDecimal (blogid) ؛ جلسة SQLSession = sqlsessionfactory.opensession () ؛ bloginfo bloginfo = new bloginfo () ؛ // 1. الاستعلام عن كائن المدونة وفقًا لـ blogid وقم بتعيين القيمة إلى bloginfo blog session. bloginfo.setBlogid (blog.getBlogid ()) ؛ bloginfo.settitle (blog.getTitle ()) ؛ // 2. وفقًا للمؤلف في المدونة ، أدخل قاعدة البيانات للاستعلام عن معلومات المؤلف وضبط النتيجة على مؤلف كائن bloginfo = (المؤلف) Session.selectone ("com.foo.bean.authormapper.selectbyprimarykey" ، blog.getauthorid ()) ؛ bloginfo.setauthor (مؤلف) ؛ // 3. الاستعلام عن كائن المشاركات وقم بتعيينه في منشورات قائمة bloginfo = session.selectlist ("com.foo.bean.postmapper.selectbyblogid" ، blog.getblogid ()) ؛ blogInfo.setPosts (المشاركات) ؛ // اطبع الكائن في شكل كائن jsonobject jsonoBject = new JSonObject (bloginfo) ؛ system.out.println (object.toString ()) ؛ إرجاع bloginfo ؛ }من الكود أعلاه ، يمكننا أن نرى أنه من المثير للقلق الحصول على كائن bloginfo. يجب عليك الاتصال باستعلام قاعدة البيانات ثلاث مرات في المجموع ، والحصول على المعلومات المطلوبة ، ثم تجميع كائن bloginfo.
استعلام البيان المتداخل
يوفر MyBatis آلية تسمى استعلام البيان المتداخل ، والتي يمكن أن تبسيط العمليات المذكورة أعلاه بشكل كبير ، وإضافة التكوين والرمز على النحو التالي:
<resultmap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id column = "blog_id" property = "blogid" /> <result column = "title" property = "title" /> <ensivanation property = "upution" column = "blog_author_id" javatype = "com.foo. SELECT = "com.foo.bean.authormapper.selectbyprimarykey"> </sirection> <collection property = "posts" column = "blog_id" oftype = "com.foo.bean.post" select = "com.foo.bean.postmapper.selectbyblogid">//resultmap> resultmap = "bloginfo" parametertype = "java.math.bigdecimal"> Select B.Blog_ID ، B.Title ، B.Author_id as blog_author_id من louluan.blog b حيث blog_id = #{blogid ، jdbctype = decimal} /** احصل على كائن bloginfo من خلال blogid*/ public static bloginfo nestedQueryEntest (String blogid) {BigDecimal id = new BigDecimal (blogid) ؛ جلسة SQLSession = sqlsessionfactory.opensession () ؛ bloginfo bloginfo = new bloginfo () ؛ bloginfo = (bloginfo) session.selectone ("com.foo.bean.blogmapper.querybloginfobyid" ، id) ؛ JSonObject Object = New JSonObject (bloginfo) ؛ system.out.println (object.toString ()) ؛ إرجاع bloginfo ؛ }يمكن تحقيق الاستعلام السابق بالكامل من خلال الكود أعلاه. هنا نحتاج فقط إلى bloginfo = (bloginfo) session.selectone ("com.foo.bean.blogmapper.querybloginfobyid" ، id) ؛ في الكود ، يمكننا الحصول على كائن bloginfo معقد.
مبدأ استعلام البيان المتداخل
في الكود أعلاه ، سيقوم MyBatis بإجراء العملية التالية:
1. قم أولاً بتنفيذ البيان المقابل لـ QueryBlogInFobyID للحصول على مجموعة نتائج النتائج من جدول المدونة ؛
2. قم بإخراج السجل الصحيح التالي من ResultSet ، ثم قم بإنشاء كائن BlogInfo المقابل استنادًا إلى مواصفات التعيين المحددة بواسطة ResultMap.
3. عندما تريد تعيين سمة المؤلف في bloginfo ، ستجد أن هناك استعلامًا مرتبطًا. في هذا الوقت ، ستقوم MyBatis أولاً بتنفيذ عبارة Select Query للحصول على النتيجة التي تم إرجاعها وتعيين النتيجة على سمة المؤلف لـ bloginfo ؛
4. عند تعيين منشورات bloginfo ، توجد عمليات مماثلة أيضًا.
5. كرر 2 خطوات حتى ResultSet. التالي () == خطأ ؛
فيما يلي مخطط تخطيطي لعملية تخصيص بناء كائنات bloginfo:
تتمثل وظيفة جيدة جدًا لهذا النوع من الاستعلام المتداخلة المرتبطة في أنه يمكنه إعادة استخدام عبارة SELECT وإنشاء كائنات معقدة من خلال المزيج بين عبارات الاختيار البسيطة. يمكن استخدام اثنين من البيانات المختارة أعلاه com.foo.bean.authormapper.selectbyprimarykey و com.foo.bean.postmapper.selectbyblogid بشكل مستقل.
مشكلة N+1
عيوبها واضحة أيضًا: ما يسمى مشكلة N+1. يُظهر الاستعلام المتداخل المرتبط بمجموعة نتائج ، ثم يتم إجراء الاستعلام المرتبط به بناءً على كل سجل من مجموعة النتائج هذه.
لنفترض الآن أن هناك استعلامًا متداخلًا واحدًا فقط (أي ، هناك علامة ارتباط داخل ResultMap) ، وعدد الإدخالات التي يتم إرجاعها بواسطة الاستعلام هو n ، ثم سيتم تنفيذ بيان الاستعلام المرتبط بالمرات n ، بالإضافة إلى أن الاستعلام نفسه يعود إلى النتيجة التي تم تعيينها إلى Query مرة واحدة ، ويطلب إجمالي عدد المرات N+1 للوصول إلى البيانات. إذا كان N كبيرًا نسبيًا ، فإن استهلاك الوصول إلى قاعدة البيانات هذا كبير جدًا! لذلك ، يجب على المستخدمين الذين يستخدمون هذا النوع من استعلام البيان المتداخل النظر بعناية لضمان أن قيمة N ليست كبيرة جدًا.
على سبيل المثال ، ستعود عبارة SELECT نفسها إلى نتائج مع com.foo.bean.blogmapper.querybloginfobyid مع 1. نظرًا لأنه يحتوي على استفسارين من العبارات ذات الصلة ، فإنه يحتاج إلى الوصول إلى قاعدة البيانات 1* (1+1) = 3 مرات في المجموع.
استفسار نتيجة متداخلة
يمكن أن يسبب الاستعلام عن البيانات المتداخلة أوقات وصول غير مؤكدة لقاعدة البيانات ، مما قد يؤثر على الأداء. يدعم MyBatis أيضًا نوعًا من الاستعلام المتداخلة: أي للاستعلام عن شخص واحد ، والعديد من المواقف ، والعديد من المواقف ، يبحث MyBatis في النتائج من قاعدة البيانات في وقت واحد من خلال الاستعلام المشترك ، ثم يحول النتائج المطلوبة إلى العدد إلى العدد إلى واحد ، والعديد من العلاقة بين الرجال وتكوينها في النتيجة ، وتصنيعها.
إعادة تعريف خريطة نتيجة bloginfo
<resultmap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id column = "blog_id" property = "blogid"/> <result column = "title" property = "title"/> <insinening property = "explive" column = "blog_author_id" javatype = "com.bean. column = "user_name" property = "username"/> <result column = "password" property = "password"/> <result column = "email" property = "email"/> <result column = "comperation" property = "ciroghar <result column = "blog_id" property = "blogid"/> <result column = "create_time" property = "createTime"/> <result column = "موضوع" property = "الموضوع"/> <result column = "body" property = "body"/> <result column = "draft" property =
عبارات SQL المقابلة هي كما يلي:
<SELECT ID = "QueryAllBlogInfo" resultmap = "bloginfo"> Select B.Blog_id ، B.Title ، B.Author_id as blog_author_id ، a.author_id ، a.user_name ، a.password ، a.email ، a.biography ، p.post_id ، p.blog_id as blog_id ، p.create ، اليسار join join uptor a on b.author_id = a.author_id اليسار الخارجي Join Post p على p.blog_id =
/** احصل على جميع المعلومات حول جميع المدونات*/ public static bloginfo nestedResultontest () {sqlsession session = sqlsessionfactory.opensession () ؛ bloginfo bloginfo = new bloginfo () ؛ bloginfo = (bloginfo) session.selectone ("com.foo.bean.blogmapper.queryallbloginfo") ؛ JSonObject Object = New JSonObject (bloginfo) ؛ system.out.println (object.toString ()) ؛ إرجاع bloginfo ؛ } خطوات التنفيذ لاستعلام النتائج المتداخلة:
1. أداء عمليات الانضمام بناءً على العلاقة المقابلة للجدول للحصول على مجموعة النتائج ؛
2. وفقًا لمعلومات مجموعة النتائج ومعلومات تعريف ResultMap لـ bloginfo ، قم بتجميع وتعيين النتيجة التي تم إرجاعها في الذاكرة لبناء bloginfo ؛
3. إرجاع قائمة النتائج التي تم إنشاؤها <BloginFo>.
بالنسبة لاستعلام النتيجة المرتبطة ، إذا كانت علاقة كثيرة ، فسيتم تكوينها بواسطة Column = "Assistr Property =" Author "=" blog_author_id "javatype =" com.foo.bean.author ">. ستجلب MyBatis البيانات من الذاكرة من خلال قيمة uplor_id المقابلة لخاصية العمود وتغليفها في كائن مؤلف ؛
إذا كانت علاقة واحدة إلى أقراص ، تمامًا مثل العلاقة بين المدونة والنشر ، يتم تكوينها بواسطة Collection Property = "Posts" Column = "blog_post_id" oftype = "com.foo.bean.post"> ، يستخدم MyBatis blog_id لجلب كائنات المنشورات في الذاكرة في قائمة <post> ؛
للاستعلام عن النتائج المرتبطة بها ، تحتاج فقط إلى الاستعلام عن قاعدة البيانات مرة واحدة ، ثم يتم وضع تكامل وتجميع النتائج في الذاكرة.
ما ورد أعلاه هو إظهار معالجة الكائنات من شخص واحد إلى واحد إلى واحد من خلال الاستعلام عن جميع معلومات المدونة.
ملاحظة: مثال على رسم الخرائط للذات:
فئة الكيان
وحدة الفئة العامة {private int id ؛ مفتاح السلسلة الخاص ؛ اسم السلسلة الخاصة ؛ الوحدة الخاصة ParentModule ؛ قائمة خاصة <Medule> kndformodules ؛ عنوان URL الخاص بالسلسلة ؛ نوع int الخاص عرض سلسلة خاصة سلسلة خاصة ديل ؛ public int getId () {return id ؛ } public void setId (int id) {this.id = id ؛ } السلسلة العامة getKey () {return Key ؛ } public void setKey (مفتاح سلسلة) {this.key = key ؛ } السلسلة العامة getName () {return name ؛ } public void setName (اسم السلسلة) {this.name = name ؛ } الوحدة العامة getParentModule () {return ParentModule ؛ } public void setParentModule (الوحدة النمطية ParentModule) {this.parentModule = parentModule ؛ } السلسلة العامة geturl () {return url ؛ } public void seturl (url url) {this.url = url ؛ } public int getort () {return sort ؛ } public void setSort (int sort) {this.sort = sort ؛ } سلسلة عامة getShow () {return Show ؛ } public void setShow (show show) {this.show = show ؛ } السلسلة العامة getDel () {return del ؛ } public void setDel (String del) {this.del = del ؛ } القائمة العامة <Module> getChildrenModules () {return kndformodules ؛ } public void setChildrenModules (قائمة <Medule> kndformodules) {this.childrenmodules = kndringmodules ؛ }} رمز XML: <mapper namespace = "com.sagaware.caraccess.mapper.modulemapper"> <resultmap type = "module" id = "moduleresultmap"> <id property = "id" column = "module_id"/> column = "module_url"/> <result property = "sort" column = "module_sort"/> <result property = "show" column = "module_show"/> <result property = "del" column = "module_del"/> <! submodule-> <collection property = "knidsmodules" column = "module_id" select = "getChildRenModules"/> </shentermap> <select id = "getModules" parametertype = "string" resultMap = "moduleresultmap"> select * from tb_module where module_id = 2 </select> parametertype = "int" resultmap = "moduleresultmap"> حدد * من tb_module حيث module_id = #{module_id} </select> <تحديد معرف = "getChildrenModues" parametertype = "int" resultMap = "moduleresultmap" </mapper>