Szenario für Ausnahmegenerierung und Ausnahmeinformationen
Letzte Woche trat eine Ausnahme auf, da die generische Klasse, die die Karte implementiert, in der Mapper -Schnittstellenmethode von MyBatis verwendet wurde, und die SQL -Anweisung, die dieser Methode entspricht, verwendete auch das Foreach -Tag. Das Folgende sind die Ausnahmeinformationen:
org.apache.ibatis.exceptions.persistenceException: ### Fehleraktualisierungsdatenbank. Ursache: org.apache.ibatis.reflection.reflectionException: Es gibt keinen Getter für Eigenschaften mit dem Namen 'Key' in 'Klasse java.lang.InEger' ### Der Fehler kann org.guojing.test.test.spring.server Goods_roomnight_30days (Goods_id, checkin_room_night_30days) Werte (?,?), (?,?), (?,?), (?,?), (?) ### Ursache: org. org.apache.ibatis.exceptions.exceptionfactory.wrapexception (exceptionfactory.java:30) unter org.apache.ibatis.session.defaults.defaultsqlSession.update (defaultsqlSession.java:200) bei org.apache.ibatis.session.defaults.defaultsqlSession.insert (defaultsqlSession.java:185) unter org.apache.ibatis.binding.mapperMethod.execute (mappermethod.java:57) bei org.apache.ibatis.binding.mapperproxy.invoke (mapperproxy.java:53) bei com.sun.proxy. sun.reflect.nativemethodaccessorimpl.invoke0 (native Methode) bei sun.reflect.nativemethodaccessorimpl.invoke (nativemethodaccessorimpl.java:57) bei sun.reflect.delegatingMethodaccessorimpl.invoke (delegatingMoDocdoccact.invoke) bei DelegatingMoTro (delegatingMoTheStroy) bei (delegatingMoTroy) bei (delegatingMoTroy) bei (delegatingMectionMoThact. java.lang.reflect.method.invoke (method.java:606) unter org.junit.runners.model.frameworkMethod $ 1.runreflectiveCall (FrameworkMethod.java:47) bei org.junit.internal.runners.model.reflectiveCallable.run (reflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeexplosiv (FrameworkMethod.java:44) at bei org.junit.internal.runners.statements.invokemethod.evaluate (invokemethod.java:17) bei org.junit.internal.runners.statements org.junit.internal.runners.statements.runaFters.evaluate (Runafters.java:27) unter org.junit.runners.parentrunner.runleaf (parentunner.java:271) at org.junit.runners.blockjunit4classrunner.runchild (BlockJunit4ClassRunner.java:70) bei org.junit.runners org.junit.runners.parentrunner $ 3.run (parentunner.java:238) bei org.junit.runners.Parentrunner $ 1.Schedule (Parentrunner.java:63) at org.junit.runners.runchildren (parentunner.java:23) ATRUNNER (Parentrunner.java:23) ATRUNNER (Parentrunner.java:23) ATRUNNER (Parentrunner.java:23) ATRUNNER (Parentrunner.java:236) ATRUNNER (Parentrunner.java:236) Atrunner. org.junit.runners.parentunner.access $ 000 (parentunner.java:53) at org.junit.runners.Parentrunner $ 2. Evaluate (Parentunner.java:229) at org.junit.runners.Parentunner.run (Parentrunner (Parentrunner org.junit.runner.junitcore.run (junitcore.java:160) unter com.intellij.junit4.junit4ideatestrunner.startrunnerwithargs (junit4Ideatestrunner.java:68) bei com.intellij.rt.execution.junit.ideatestrunner $ repeater.startrunnerwithargs (ideatestrunner.java:51) unter com.intellij.rt.execution.junit.junitstarter.preparestreamsandStart (junitstarter.java:237) in com.intellij.rt.execution.junit.junitStarter.main (junitstarter.java:70) verursacht durch: org.apache.ibatis.reflection.reflectionException: Es gibt keinen Getter für die Eigenschaft namens 'Schlüssel' in 'klassen java.lang.intierger' bei atgerger 'at' at at AT bei AT bei AT bei org.apache.ibatis.reflection.reflector.getgetInvoker (Reflector.java:409) unter org.apache.ibatis.reflection.metacklass.getgetInvoker (metaclass.java:164) unter org.apache.ibatis.reflection.wrapper.beanwrapper.getbeanProperty (beanwrapper.java:162) unter org.apache.ibatis.reflection.wrapper.beanwrapper.get (Beanwrapper.java:49) unter org.apache.ibatis.reflection.metaObject.getValue (metaObject.java:122) at org.apache.ibatis.reflection.metaObject.getValue (metaObject.java:119) at org.apache. org.apache.ibatis.scripting.defaults.defaultParameterhandler.setParameters (DefaultParameterhandler.java:72) unter org.apache.ibatis.executor.statement.preparedStatementHandler.Parameterize (vorbereitete Stellungs- und Java:93) ATREPERTE org.apache.ibatis.executor.statement.routingStatementHandler.Parameterize (RoutingStatementHandler.java:64) unter org.apache.ibatis.executor.simpleExecutor.preparestatement (Simplexecutor.java:86) unter untergebracht) unter org.apache.ibatis.executor.simpleexexecutor.doupdate (Simpleexecutor.java:49) unter org.apache.ibatis.executor.basexexexecutor.update (Baseexexecutor.java:117) bei org.apache.ibatis.session.defaults.defaultSQlSession.update (defaultSQLSession.java:198) ... 29 More
Da ich nicht viel über MyBatis weiß, habe ich lange gebraucht, um die spezifische Ursache der Anomalie herauszufinden.
Als nächstes werde ich die Ausnahme reproduzieren und die Ursachen der Ausnahme analysieren.
Ausnahme taucht wieder auf
Um die obige Ausnahme zu reproduzieren, wurde eine Demo geschrieben. Die relevanten Codes sind wie folgt:
Datenbanktabellenstruktur:
Erstellen Sie Tabelle `goods_roomnight_30days` (` goods_id` bigint (20) nicht null, `checkin_room_night_30days` int (11) nicht null Standard '0' Kommentar 'Kommentar' letzte 30-Tage-Nacht ', Primärschlüssel (` garge_id`)
KeyValue.java Parameterklasse:
public class keyValue <k, v> implements map.Entry <k, v> {private k key; privater V -Wert; public keyValue () {} public keyValue (k key, v value) {this.key = key; this.Value = Wert; } @Override public k getKey () {return key; } @Override public v getValue () {Rückgabewert; } @Override public v setValue (V -Wert) {v oldValue = this.value; this.Value = Wert; kehren Sie OldValue zurück; } public JsonObject tojsonObject () {return ReportJsonObject.NewObject (). append (String.ValueOf (Schlüssel), Wert); } @Override public String toString () {return tojsonObject (). Tojonstring (); }}Dao Class Goodsroomnight30 -DaysMapper.java
öffentliche Schnittstelle Ware Roomnight30DaysMapper {int deleteByExample (Beispiel für die ROUNGSROOMORMAGE30 DaysExample); Liste <Goodroomnight30 -Tage> SelectByExample (Beispiel für die Roomnight30daysexample); <K, v> intbatch (Liste <KeyValue <k, v >> Datensätze);}mybatis-config.xml Datei:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <settings> <setting name="cacheEnabled" value="false"/> < /settings> <!-Nach der Integration mit Spring wird die Konfiguration der Umgebungen abgeschafft und an die Spring-Management übergeben-> <Umgebungen default = "Development"> <Environment ID = "Development"> <!-Verwenden Sie JDBC Transaction Transaction Management-> <TransactionManager Typ = "JDBC" /> <! name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/hotel_report?characterEncoding=utf-8" /> <property name="username" value="test_user" /> <property name="password" value="user123" /> </dataSource> </Umwelt> </Umgebungen> <mappers> <mapper resource = "mybatis/goodroomnight30daysmapper.xml"/> </mappers> </configuration>
Der Hauptinhalt der Warenroomnight30 -DaysMapper.xml -Datei:
<insert id="insertBatch" parameterType="list"> REPLACE INTO goods_roomnight_30days (goods_id, checkin_room_night_30days) VALUES <foreach collection="list" index="index" item="item" separator=","> (#{item.key}, #{item.value}) <!--<choose>--> <!--<when test="item.value == NULL "> (#{item.key}, 0) </wenn>-> <!-<wenn test =" item.value!Das obige ist der Hauptcode für die Reproduktion dieser Ausnahme. Der vollständige Code kann unter GitHub angezeigt werden: https://github.com/misterzhou/java-demo/tree/master/test-spring/spring-server
Testcode, der die Ausnahme der Ausnahme von Goodroomnight30 -Daystest.java reproduziert:
Paket org.guojing.test.spring.server; import org.apache.ibatis.io.resources; import org.apache.ibatis.Session org.apache.ibatis.session.sqlSessionFactoryBuilder; import org.guojing.spring.commons.keyValue; import org.junit.after; java.util.list;/** * Erstellt unter: 2016-12-24 * * @author Guojing */öffentliche Klassenroomnight30daystest {SQLSessionFactory SQLSessionFactory; SQLSession SQLSession; Warenroomnight30 -DaysMapper Ware Roomnight30 -DaysMapper; @Before public void init () löst IOException aus {String ressourcen = "mybatis/mybatis-config.xml"; InputStream InputStream = Ressourcen.getResourceAsStream (Ressource); SQLSessionFactory = new SQLSessionFactoryBuilder (). Build (InputStream); sqlSession = sqlSessionFactory.openSession (true); Warenroomnight30 -DaysMapper = sqlSession.getMapper (Warenraumnacht30 -Tage -Mapper.Class); } @Test public void test () {list <KeyValue <lang, ganz, integer >> records = new ArrayList <> (); Records.Add (neuer KeyValue <Long, Integer> (1725L, 5)); Records.Add (neuer KeyValue <Long, Integer> (1728L, 3)); Records.Add (neuer KeyValue <Long, Integer> (1730L, NULL)); Records.Add (neuer KeyValue <Long, Integer> (1758L, NULL)); int deleted = roodroomnight30daysMapper.DeleteByExample (neue Warenroomnight30daysexample ()); System.out.println ("----- gelöschte Zeilengröße:" + gelöscht); int Row = Goodroomnight30 -DaysMapper.insertBatch (Records); System.out.println ("----- betroffene Zeile:" + row); Liste <Goodroomnight30 Tage> Ergebnis = Warenraumnacht30 -Tage -Mapper.SelectByExample (New Goodroomnight30daysexample ()); für (Goodroomnight30 -Tage -Artikel: Ergebnis) {System.out.println (item.toString ()); }} @After public void After () {if (sqlSession! = Null) {sqlSession.close (); }}}Lassen Sie es uns geheim halten, schauen Sie nicht zuerst nach unten und denken Sie über die Ursachen der Abnormalität nach (Schüler, die das Foreach -Tag mithalten können, sollten in der Lage sein, die Hinweise zu sehen).
Ausnahmeprozess und Ausnahmeanalyse
Da die Parameterklasse und die Rückgabeergebnisklasse der DAO -Methode häufig einen Wert entsprechen, der dem Schlüssel und Schlüssel entspricht, um die Klasse wiederholt zu vermeiden, definierte ich eine generische KeyValue -Klasse, die die MAP.Enty -Schnittstelle implementiert. Weitere Informationen finden Sie im vorherigen Abschnitt.
GoodsRoomnight30daysMapper.insertBatch() -Methode verwendet diese generische Klasse. Nach dem Laufen werden die zu Beginn dieses Artikels genannten Ausnahmeinformationen geworfen.
Nachdem ich die Ausnahmeinformationen gesehen hatte, konzentrierte ich mich darauf, ob MyBatis 'Unterstützung für Generika nicht gut genug ist. Ich fragte meinen Kollegen (@shengelnan), und mein Kollege versuchte es auf seiner Maschine und stellte fest, dass es keine Abnormalität gab. Das ist seltsam. Nach einem genaueren Blick auf den Code stellte ich fest, dass der Unterschied darin besteht, dass meine generische KeyValue -Klasse die MAP.Entry -Schnittstelle implementiert. Zu diesem Zeitpunkt kenne ich die Beschreibung des Foreach -Tags auf der offiziellen Website von MyBatis nicht:
Jedes iterable Objekt (z. B. Listen, Sammlungen usw.) und jedes Wörterbuch- oder Array -Objekt kann als Sammelparameter an foreach übergeben werden. Bei Verwendung eines iterbaren Objekts oder Arrays ist der Index die Anzahl der Iteraten, und der Wert des Elements ist das in dieser Iteration erhaltene Element. Bei Verwendung eines Wörterbuchs (oder einer Sammlung von MAP.Entry -Objekten) ist der Index der Schlüssel und das Element ist der Wert.
Überprüfen Sie als nächstes die spezifischen Gründe für die Ausnahme durch Debug. Daher habe ich zuerst den Code der KeyValue -Klasse verwendet, die die MAP.Enty -Schnittstelle zum Debuggen implementiert. Durch das Ausnahmeprotokoll kann ich feststellen, dass die Ausnahme in Zeile defaultsqlSession.java:200 ausgelöst wird, also habe ich den Breakpoint to Line defaultsqlSession.java:197 getroffen und es dann Schritt für Schritt ausgeführt. Als ich es zur Linie für Eachsqlnode.java:73 ausführte, wurde es endlich klar. Schauen wir uns zuerst das Debug -Call -Ketten -Diagramm an:
Schauen wir uns den spezifischen Code für Eachsqlnode.java:73 an (diese Klasse ist die Knotenklasse des Foreach -Tag -Objekts):
Zu diesem Zeitpunkt ist die spezifische Ursache der Ausnahme sehr offensichtlich. Die Klasse, zu der das O -Objekt hier gehört, ist die KeyValue -Klasse. Da die KeyValue -Klasse die MAP.Entry -Schnittstelle implementiert, ist ONTANCE MAP.Entry true, myBatis weist dem Indexattribut von foreach den Schlüsselwert zu und weist dem Element -Attribut den Wert zu. Hier wird das Ganzzahlobjekt mit einem Wert von 5 dem Element -Attribut zugewiesen. Daher hat das entsprechende Objekt, das dem Element -Attribut des Select -Tags mit InsertBatch in Warenroomnight30daysMapper.xml entspricht, nicht über den Element.Key und Item.Value -Attribute, was die ultimative Ursache der Ausnahme ist.
<einfügen id = "insertBatch" parameterType = "list"> in goods_roomnight_30days (Goods_id, checkin_room_oom_night_30days) Werte <foreach collection = "list" index = "index" item = "item" separator = "> ( #{item.key}, #{item.value}) </foreach> </foreach> </foreach>Die oben genannten ist eine kurze Analyse der Gründe, warum das MyBatis foreach -Tag nicht ordnungsgemäß verwendet wird, und ich hoffe, dass es Ihnen hilfreich ist. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Editor wird Ihnen rechtzeitig antworten. Vielen Dank für Ihre Unterstützung auf der Wulin.com -Website!