سيناريو توليد الاستثناء ومعلومات الاستثناء
في الأسبوع الماضي ، حدث استثناء لأن الفئة العامة التي تنفذ الخريطة. تم استخدام واجهة الدخول في طريقة واجهة Mappatis 'Mappatis ، واستخدمت عبارة SQL المقابلة لهذه الطريقة أيضًا علامة foreach. فيما يلي معلومات الاستثناء:
org.apache.ibatis.exceptions.persistenceException: ### خطأ تحديث قاعدة البيانات. السبب: org.apache.ibatis.reflection.reflectionException: لا يوجد أي getter للممتلكات المسمى "مفتاح" في class java.lang.integer '### قد يتضمن الخطأ org.guojing.test.spring.server.goodsroomnight30daysmapper.insert-inline ## ood ke oo the lood ad parameTers#ood. goods_roomnight_30days (goods_id ، checkin_room_night_night_30days) القيم (؟ ،؟) ، (؟ ،؟) ، (؟ ،؟) ، (؟ ،؟) ، (؟ ،؟) org.apache.ibatis.exceptions.exceptionfactory.wrapexception (استثناء factory. org.apache.ibatis.session.defaults.defaultsqlsession.insert (defaultsqlsession.java:185) على org.apache.ibatis.binding.mappermethod.execute (mappermethod.java:57) على org.apache.ibatis.binding.mapperproxy.invoke (mapperproxy.java:53) في com.sun.proxy. Sun.Reflect.NativeMethodAccessorImpl.Invoke0 (الطريقة الأصلية) في Sun.Reflect.NativeMethodAccessorImpl.invoke (NativeMethodaccessorImpl.java:57) في Sun.Reflect.DelegatingMetactorImpl.invoke (DelegatingmatorImpl. java.lang.reflect.method.invoke (method.java:606) at org.junit.runners.model.frameworkmethod $ 1.runreflectiveCall (Frameworkmethod.java:47) في org.junit.internal.runners.model.reflectivecallable.run (respectivecallable.java:12) at org.junit.runners.model.frameworkmethod.invokeexplosively (Frameworkmethod.java:44) org.junit.internal.runners.statements.invokemethod.evaluate (invokemethod.java:17) at org.junit.internal.runners.statements.runbefores.evalate (Runbefores.java:26) at org.junit.internal.runners.statements.runafters.evaltuer (runafters.java:27) at org.junit.runners.parentrunner.runleaf (parentrunner.java:271) at org.junit.runners.blockjunit4classrunner.runchild (blockjunit4classrunner.java:70) في org.junit.runners.blockjunit4classrunner.runchild (blockjunit4classrunner.java:50) org.junit.runners.parentrunner $ 3.run (parentrunner.java:238) at org.junit.runners.parentrunner $ 1.Schedule (parentrunner.java:63) at org.junit.runners.parentrunner.runchildren ( org.junit.runners.parentrunner.access 000 دولار (parentrunner.java:53) في org.junit.runners.parentrunner 2. Evaluer org.junit.runner.junitcore.run (junitcore.java:160) في com.intellij.junit4.junit4ideatestrunner.startrunnerwithargs com.intellij.rt.execution.junit.ideatestrunner $ Repeater.StarTrunnerWithargs (ideatestrunner.java:51) على com.intellij.rt.execution.junit.junitstarter.preparestramsand (junitstarter.java:237) at com.intellij.rt.execution.junit.junitstarter.main (junitstarter.java:70) الناجم عن: org.apache.ibatis.reflection.reflection: لا يوجد getter لعقار اسم "key 'في' java.lang.integer 'في org.apache.ibatis.reflection.reflector.getgetInvoker (Reflector.java:409) at org.apache.ibatis.reflection.metaclass.getgetinvoker (metaclass.java:164) في org.apache.ibatis.reflection.wrapper.beanwrapper.getBeanProperty (beanwrapper.java:162) at org.apache.ibatis.reflection.wrapper.beanwrapper.get (beanwrapper.java:49) على org.apache.ibatis.reflection.metaobject.getValue (metaObject.java:122) at org.apache.ibatis.reflection.metaobject.getValue (metaobject.java:119) في org.apache.ibatis.mapping.boundsql.getadditional. org.apache.ibatis.scripting.defaults.defaultparameterhandler.setParameters (defaultParameterHandler.java:72) على org.apache.ibatis.executor.statement.preparedStatehandler.Parameterize (predaredStatementHandler.java:93) org.apache.ibatis.executor.statement.RoutingStateMentHandler.Parameterize (RoutingStateMentHandler.java:64) على org.apache.ibatis.executor.simpleexecutor.preparestatement (SimpleExecutor.java:86) org.apache.ibatis.executor.simpleexecutor.doupdate (simpleexecutor.java:49) at org.apache.ibatis.executor.baseexecutor.update (baseexecutor.java:117) on org.apache.ibatis.session.defaults.defaultsqlsession.update (defaultsqlsession.java:198) ... 29 المزيد
لأنني لا أعرف الكثير عن MyBatis ، فقد استغرق الأمر وقتًا طويلاً للتصحيح ومعرفة السبب المحدد للخلل.
بعد ذلك ، سأعيد إنتاج الاستثناء وأحلل أسباب الاستثناء.
استثناء الظهور
من أجل إعادة إنتاج الاستثناء أعلاه ، تمت كتابة العرض التوضيحي. الرموز ذات الصلة هي كما يلي:
هيكل جدول قاعدة البيانات:
قم بإنشاء جدول `good_roomnight_30days` (` `gouds_id` bigint (20) not null ،` checkin_night_night_30days` int (11) not null '0' comment 'last 30 day night' ، chain in `goods_id`)) engine = innodb default charset = utf8 comment =" السلع "الماضي 30-day night"
keyvalue.java فئة المعلمة:
keyvalue الفئة العامة <K ، V> تنفذ map.entry <k ، v> {private k key ؛ قيمة V الخاصة ؛ public keyvalue () {} keyvalue public (k key ، v value) {this.key = key ؛ this.value = القيمة ؛ } Override public k getKey () {return Key ؛ } Override public v getValue () {return value ؛ } Override public v setValue (v value) {v oldvalue = this.value ؛ this.value = القيمة ؛ إرجاع Oldvalue ؛ } jsonobject public tojsonoBject () {return reportJsonObject.newObject (). append (string.valueof (key) ، value) ؛ } Override public string toString () {return tojsonobject (). tojsonstring () ؛ }}DAO CLASS GOUSSROOMNEY30DAYSMAPPER.JAVA
الواجهة العامة goodsroomnight30daysmapper {int deletebyexample (pouldroomnight30daysexample مثال) ؛ قائمة <Gombroomnight30days> SelectByexample (GouthRoomnight30daySexample مثال) ؛ <k ، v> int insertbatch (قائمة <keyvalue <k ، v >> السجلات) ؛}ملف mybatis-config.xml:
<؟ < /settings> <!-بعد التكامل مع الربيع ، سيتم إلغاء تكوين البيئات وتسليمه إلى إدارة الربيع-> <البيئات default = "development"> <البيئة معرف = "التطوير"> <!-استخدم إدارة معاملة JDBC-> <المعاملات type = "jdbc" /> <! <property name = "driver" value = "com.mysql.jdbc.driver" /> <property name = "url" value = "jdbc: mysql: // localhost: 3306 /hotel_report؟ </visply> </eversionments> <mappers> <mapper resource = "mybatis/goodroomnightnight30daysmapper.xml"/> </mappers> </iscification>
المحتويات الرئيسية لـ goodroomnight30daysmapper.xml ملف:
<insert id = "insertBatch" parametertype = "list"> استبداله في good_roomnight_30days (goods_id ، checkin_room_night_30days) القيم <foreach collection = "list" index = "index" item = "item =" expanator = "،" ( #{item.key} ، #{ite. NULL "> (#{item.key} ، 0) </hen>-> <!-<عندما test =" item.value! = null "> (#{item.key} ،#{item.value}) </when>-> <!-ما سبق هو الرمز الرئيسي لاستنساخ هذا الاستثناء. يمكن عرض الرمز الكامل على github: https://github.com/misterzhou/java-demo/tree/test-spring/spring-server
رمز الاختبار الذي يعيد إنتاج استثناءات goodroomnight30daystest.java:
package org.guojing.test.spring.server ؛ import org.apache.ibatis.io.resources ؛ import org.apache.ibatis.session.sqlsession ؛ import org.apache.ibatis.session.sqlsessionfactory ؛ org.apache.ibatis.session.sqlsessionfactorybuilder ؛ import org.guojing.spring.commons.keyvalue ؛ import org.junit.after ؛ import org.junit.ebore ؛ java.util.list ؛/** * تم إنشاؤه على: 2016-12-24 * * Auuthor Guojing */public class goodsroomnight30daystest {sqlsessionfactory sqlsessionfactory ؛ sqlsession sqlsession ؛ Goodroomnight30daysmapper goodroomnight30daysmapper ؛ before public void init () يلقي ioException {String Resource = "MyBatis/MyBatis-Config.xml" ؛ inputStream inputStream = resources.getResourCeasStream (Resource) ؛ sqlsessionfactory = جديد sqlsessionfactorybuilder (). build (inputStream) ؛ sqlsession = sqlsessionfactory.opensession (true) ؛ goodroomnight30daysmapper = sqlsession.getMapper (goodroomnight30daysmapper.class) ؛ } test public void test () {list <keyvalue <long ، integer >> records = new ArrayList <> () ؛ records.add (new keyvalue <long ، integer> (1725L ، 5)) ؛ records.add (new keyvalue <long ، integer> (1728l ، 3)) ؛ records.add (new keyvalue <long ، integer> (1730l ، null)) ؛ records.add (new keyvalue <long ، integer> (1758l ، null)) ؛ int deleted = goodroomnight30daysmapper.deleteByExample (New GoodRoomNight30daySexample ()) ؛ System.out.println ("----- حجم الصف المحذوف:" + حذف) ؛ int row = goodroomnight30daysmapper.insertbatch (السجلات) ؛ System.out.println ("----- الصف المتأثر:" + صف) ؛ قائمة <EgelSroomnight30days> النتيجة = goodroomnight30daysmapper.SelectByExample (New GoodSroomnight30daySexample ()) ؛ لـ (pouldroomnight30days البند: النتيجة) {system.out.println (item.ToString ()) ؛ }} apter public void بعد () {if (sqlsession! = null) {sqlsession.close () ؛ }}}دعونا نبقيه سراً ، لا تنظر أولاً ، فكر في أسباب الشذوذ (يجب أن يكون الطلاب المبرقون في استخدام علامة foreach قادرين على رؤية القرائن).
عملية الاستثناء وتحليل الاستثناء
في المشروع ، نظرًا لأن فئة المعلمة ونتيجة الإرجاع في غالبًا ما تحتوي طريقة DAO على قيمة تتوافق مع المفتاح والمفتاح ، من أجل تجنب تحديد الفئة بشكل متكرر ، فقد حددت فئة عامة مفتاحية تنفذ واجهة الخريطة. لمزيد من التفاصيل ، يرجى الاطلاع على القسم السابق.
تستخدم طريقة GoodsRoomnight30daysMapper.insertBatch() هذه الفئة العامة. بعد الجري ، يتم إلقاء معلومات الاستثناء المذكورة في بداية هذه المقالة.
بعد رؤية معلومات الاستثناء ، ركزت على ما إذا كان دعم MyBatis للأشكال غير جيدة بما فيه الكفاية. سألت زميلي (shengnan) ، وتجربته زميلي على جهازه ووجدت أنه لا يوجد خلل. هذا غريب. بعد إلقاء نظرة فاحصة على الكود ، وجدت أن الفرق هو أن فئة المفاتيح العامة الخاصة بي تنفذ الخريطة. في هذا الوقت ، لا أعرف الإرشادات الموجودة على علامة foreach على موقع MyBatis الرسمي:
يمكن تمرير أي كائن أمر لا يطاق (مثل القوائم ، والمجموعات ، وما إلى ذلك) وأي كائن قاموس أو صفيف إلى Foreach كمعلمات تجميع. عند استخدام كائن أو صفيف غير قابلة للتأثير ، يكون الفهرس هو عدد المرات المتكررة ، وقيمة العنصر هي العنصر الذي تم الحصول عليه في هذا التكرار. عند استخدام قاموس (أو مجموعة من كائنات الخريطة) ، يكون الفهرس هو المفتاح والبند هو القيمة.
بعد ذلك ، تحقق من الأسباب المحددة للاستثناء من خلال التصحيح. لذلك استخدمت لأول مرة رمز فئة Keyvalue التي تنفذ واجهة الخريطة. من خلال سجل الاستثناء ، أستطيع أن أرى أن الاستثناء يتم إلقاؤه في خط DefaultSqlSession.java:200 ، لذلك ضربت نقطة الإيقاف إلى Line DefaultSqlsession.java:197 ، ثم قمت بتنفيذها خطوة بخطوة. عندما قمت بإعدادها إلى خط foreachsqlnode.java:73 ، أدركت ذلك أخيرًا. دعونا نلقي نظرة على مخطط سلسلة مكالمات التصحيح أولاً:
دعونا نلقي نظرة على الكود المحدد foreachsqlnode.java:73 (هذه الفئة هي فئة العقدة لكائن علامة foreach):
في هذا الوقت ، يكون السبب المحدد للاستثناء واضحًا للغاية. الفئة التي ينتمي إليها كائن O هنا هي فئة KeyValue. نظرًا لأن فئة Keyvalue تنفذ MAP.entry واجهة ، فإن O -extal map.entry صحيح ، يقوم MyBatis بتعيين قيمة المفتاح إلى سمة الفهرس لـ foreach ، ويعين القيمة إلى سمة العنصر. هنا ، يتم تعيين كائن عدد صحيح بقيمة 5 إلى سمة العنصر. لذلك ، فإن الكائن المقابل المقابل لسمة العنصر الخاصة بعلامة SELECT مع insertbatch في goodroomnight30daysmapper.xml لا يحتوي على العنصر.
<insert id = "insertBatch" parametertype = "list"> استبداله في good_roomnight_30days (goods_id ، checkin_room_night_30days) القيم <foreach collection = "list" index = "index" item = "item" ، exert> ، "
ما سبق هو تحليل موجز لأسباب يتم استخدام علامة MyBatis Foreach بشكل غير صحيح ، وآمل أن تكون مفيدة لك. إذا كان لديك أي أسئلة ، فيرجى ترك رسالة لي وسوف يرد المحرر إليك في الوقت المناسب. شكرا جزيلا لدعمكم لموقع wulin.com!