Сценарий генерации исключений и исключение
На прошлой неделе произошло исключение из -за того, что общий класс, который реализует интерфейс Map.Entry, использовался в методе интерфейса Mybatis Mapper, а оператор SQL, соответствующий этому методу, также использовал тег Foreach. Ниже приведена информация об исключении:
org.apache.ibatis.exceptions.persistenceexception: ### Обновление ошибок базы данных. Причина: org.apache.ibatis.reflection.reflectionexception: нет никакого Getter для свойства с именем 'key' в 'class java.lang.integer' ### Ошибка может включать в себя org.guojing.test.spring.server.goodsroom Night30daysmapper.insertbatch-inline###########Заменить#Заменить##########################Заменит. GOODE_Roomnight_30Days (GOODE_ID, CHECKIN_Room_night_30Days) значения (?,?,?), (?,?), (?,?), (?,?), (?,?) ### Причина: org.apache.ibatis.reflection.ReflectionExcept org.apache.ibatis.exceptions.exceptionFactory.WrapeXception (exceptionFactory.java:30) на org.apache.ibatis.session.defaults.defaultsqlsession.update (defaultsqlsession.java:200) org.apache.ibatis.session.defaults.defaultsqlsession.insert (defaultsqlsession.java:185) на org.apache.ibatis.cinding.mappermethod.execute (mappermethod.java:57) org.apache.ibatis.binding.mapperproxy.invoke (mapperproxy.java:53) на com.sun.proxy. sun.reflect.nativemethodaccessormpl.invoke0 (нативный метод) на sun.reflect.nativemethodaccessorimpl.invoke (nativemethodaccessorimpl.java:57) на sun.reflect.delegatingmethodaccessorimpl.invoke (DelegatingMethodaccesspormpl. java.lang.reflect.method.invoke (method.java:606) на org.junit.runners.model.frameworkmethod $ 1.RunreflectiveCall (FrameworkMethod.java:47) org.junit.internal.runners.model.reflectivecallable.run (ReflectiveBallable.java:12) на org.junit.runners.model.frameworkmethod.invokeexplosives org.junit.internal.runners.statements.invokemethod.evaluate (vokemethod.java:17) на org.junit.internal.runners.statements.runbefores.evaluate (runbefores.java:26) org.junit.internal.runners.statements.runafters.evaluate (runafters.java:27) на org.junit.runners.parentrunner.runleaf (parentrunner.java:271) 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) на org.junit.runners.parentrunner $ 1.schedule (parentrunner.java:63) на org.junit.runners.parentrunner.runner. org.junit.runners.parentrunner.access $ 000 (parentrunner.java:53) на org.junit.runners.parentrunner $ 2. evaluate (parentrunner.java:229) на org.junit.runners.parentrunner.run (parentrunner.java:309) org.junit.runner.junitcore.run (junitcore.java:160) по адресу com.intellij.junit4.junit4ideatestrunner.startrunnerwithargs (junit4ideatestrunner.java:68) у com.intellij.rt.execution.junit.ideatestrunner $ repeater.startrunnerwithargs (ideatestrunner.java:51) на com.intellij.rt.execution.junit.junitstarter.preparestreamsandstart (junitstarter.java:237) com.intellij.rt.execution.junit.junitstarter.main (junitstarter.java:70), вызванная: org.apache.ibatis.reflection.reflectionExcept org.apache.ibatis.reflection.reflector.getgetinvoker (Reflector.java:409) на org.apache.ibatis.reflection.metaclass.getgetinvoker (metaclass.java:164) на org.apache.ibatis.reflection.wrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanwrapper.beanw at org.apache.ibatis.reflection.wrapper.beanwrapper.get (beanwrapper.java:49) at org.apache.ibatis.reflection.metaobject.getvalue (metaobject.java:122) at org.apache.ibatis.reflection.metaobject.getavale.jebject. org.apache.ibatis.mapping.boundsql.getadditionalParameter (boundsql.java:75) на org.apache.ibatis.scripting.defaults.defaultparameterhandler.setParameters (defaultParameterHandler.java:72) у org.apache.ibatis.executor.statement.preparedStatementHandler.parametize (PrediveStatementHandler.java:93) at org.apache.ibatis.executor.statement.routingStatementHandler.parameterize (RoutingStatementHandler.javement.64) org.apache.ibatis.executor.simpleExecutor.prepareStatement (simpleExecutor.java:86) at org.apache.ibatis.executor.simpleexecutor.doupdate (simplexecutor.java:49) org.apache.ibatis.executor.baseexecutor.update (baseexecutor.java:117) на org.apache.ibatis.session.defaults.defaultsqlsession.update (defaultsqlsession.java:198) ... 29
Поскольку я мало знаю о Mybatis, мне потребовалось много времени, чтобы отлаживать и выяснить конкретную причину ненормальности.
Далее я воспроизведю исключение и проанализирую причины исключения.
Исключение вновь появляется
Чтобы воспроизвести вышеупомянутое исключение, было написано демонстрация. Соответствующие коды следующие:
Структура таблицы баз данных:
Создать таблицу `govel_roomnight_30days` (` govel_id` bigint (20) не null, `checkin_room_night_30days` int (11) не null по умолчанию '0' Комментарий« Последняя 30-дневная ночь », первичный ключ (` govel_id`)) Engine = innodb defall charset = utf8 Комментарий = «Товар».
Keyvalue.java Параметр класс:
открытый класс Keyvalue <K, V> реализует Map.Entry <K, V> {private K Key; частное значение V; public keyvalue () {} public Keyvalue (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; } public jsonObject tojsonObject () {return reportjsonObject.newObject (). Append (string.valueof (key), value); } @Override public String toString () {return tojsonObject (). TojSonstring (); }}DAO CLASS GOODSROONMANGE30DAYSMAPPER.JAVA
Общедоступный интерфейс Goodsroom Night30daysmapper {int deleteByexample (Goaldroom Night30daySexample Пример); Список <Goaldroomnight30days> SelectByexample (Goaldroomnight30daySexample Пример); <K, v> int insertbatch (list <keyvalue <K, v >> records);}mybatis-config.xml файл:
<? xml version = "1.0" Encoding = "UTF-8"?> <! Конфигурация doctype public "-// mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <ficination> <treats> <tatude> <treated "=" Coacheed "/" cosheed "/" cosheed "/" cosheed "/" cosheed "/" cosheed "/" cosheed "/vallabled"/vallabled "/vallabled"/"cosheed"/"cosheed"/"/" </settings> <!-- After integration with spring, the environments configuration will be abolished and handed over to spring management--> <environments default="development"> <environment id="development"> <!-- Use jdbc transaction management--> <transactionManager type="JDBC" /> <!-- Database connection pool, after integration, third-party connection pools are generally used-> <dataSource type="POOLED"> <property 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> </ervenery> </ervinements> <mappers> <mapper resource = "mybatis/govelroomname30daysmapper.xml"/> </mappers> </configuration>
Основное содержимое товара, ночи 30daysmapper.xml Файл:
<INSERT ID = "INSERTBATCH" PARAMETERTYPE = "LIST"> ЗАМЕРЖАНИЯ В GOODE_ROOMNITH_30DAYS (GOODE_ID, CHECKIN_ROME_INATE_30DAYS) <foreach Collection = "list" index = "item =" item "," separator = ","> ( #{item.key}, #{item.value}) <! == null "> (#{item.key}, 0) </when>-> <!-<when test =" item.value! = null "> (#{item.key},#{item.value}) </when>-> <!Приведенное выше является основным кодом воспроизведения этого исключения. Полный код можно просмотреть на github: https://github.com/misterzhou/java-demo/tree/master/test-spring/spring-server
Тестовый код, который воспроизводит исключение Goalsroomnomnight30dayStest.java:
пакет org.guojing.test.spring.server; import org.apache.ibatis.io.resources; import org.apache.ibatis.session.sqlsession; import org.apache.ibatis.session.ssessionFactory; импорт org.apache.ibatis.ssession.sessionFactory; org.apache.ibatis.session.sqlsessionFactoryBuilder; импорт org.guojing.spring.commons.keyvalue; импорт org.junit.after; импорт org.junit.before; импорт org.junit.test; импорт java.io.ioexcept java.util.list;/** * Создано по адресу: 2016-12-24 * * @author guojing */public class hoeldroom night30daystest {sqlSessionFactory sqlSessionFactory; SQLSession SQLSession; Goadsroom Night30daysmapper Goodsroom Night30daysmapper; @Before public void init () throws ioException {string resource = "mybatis/mybatis-config.xml"; InputStream inputStream = resources.getResourceasStream (ресурс); sqlSessionFactory = new sqlSessionFactoryBuilder (). Build (inputStream); sqlSession = sqlSessionFactory.Opensession (true); Goaldroomnight30daysmapper = sqlSession.getMapper (Goaldroom Night30daysmapper.class); } @Test public void test () {list <keyvalue <long, Integer >> Records = new ArrayList <> (); records.add (новый ключ -кв. <Long, Integer> (1725L, 5)); records.add (новая ключевая передача <long, integer> (1728l, 3)); recordss.add (new Keyvalue <long, Integer> (1730L, NULL)); records.add (новый ключевой капитал <long, integer> (1758l, null)); int deleted = Goodsroom Night30daysMapper.DeleteByExample (новый Goaldroom Night30daySexample ()); System.out.println ("----- Удаленный размер строки:" + удален); int row = Goodsroomnight30daysmapper.insertBatch (записи); System.out.println ("----- Затронутая строка:" + row); Список <dowsroom Night30days> result = Goaldroom Night30daysmapper.selectbyExample (New Goaldroom Night30daySexample ()); для (Goaldroomnight30days Пункт: Результат) {System.out.println (item.toString ()); }} @After public void After () {if (sqlSession! = Null) {sqlSession.close (); }}}Давайте храним это в секрете, не смотрим вниз в первую очередь, подумайте о причинах аномалии (студенты, которые опытны в использовании тега Foreach, должны иметь возможность видеть подсказки).
Процесс исключений и анализ исключений
В проекте, поскольку класс параметров и класс результатов возврата метода DAO часто содержит значение, соответствующее ключу и клавишу, чтобы избежать многократного определения класса, я определил общий класс KeyValue, который реализует интерфейс Map.Entry. Для получения подробной информации, пожалуйста, смотрите предыдущий раздел.
Метод GoodsRoomnight30daysMapper.insertBatch() использует этот общий класс. После запуска информация об исключении, упомянутая в начале этой статьи, брошена.
Увидев информацию об исключении, я сосредоточился на том, недостаточно ли поддержка Mybatis для Generics. Я спросил моего коллеги (@shengnan), и мой коллега попробовал это на своей машине и обнаружил, что не было ненормальности. Это странно. После более тщательного взгляда на код, я обнаружил, что разница в том, что мой общий класс KeyValue реализует интерфейс Map.Entry. В настоящее время я не знаю описания тега Foreach на официальном сайте Mybatis:
Любой итерабильный объект (например, списки, коллекции и т. Д.) И любой словарь или объект массива может быть передана в Foreach в качестве параметров сбора. При использовании итерабируемого объекта или массива индекс является итератным количеством раз, а значение элемента - это элемент, полученный в этой итерации. При использовании словаря (или коллекции объектов Map.Entry) индекс является ключом, а элемент - это значение.
Затем проверьте конкретные причины исключения через отладку. Поэтому я сначала использовал код класса KeyValue, который реализует интерфейс Map.Entry для отладки. Через журнал исключений я вижу, что исключение брошено в Line DefaultsqlSession.java:200, поэтому я попал в точку останова, чтобы линейные дефолты qultsession.java:197, а затем я выполнил ее шаг за шагом. Когда я выполнил его в линейке Foreachsqlnode.java:73, я наконец понял это. Давайте сначала посмотрим на диаграмму отладки звонков:
Давайте посмотрим на конкретный код FOREACHSQLNODE.JAVA:73 (этот класс является классом узла объекта Foreach Tag):
В настоящее время конкретная причина исключения очень очевидна. Класс, к которому принадлежит объект o, является класс KeyValue. Поскольку класс KeyValue реализует интерфейс map.Entry, o экземпляра Map.Entry является истинной, MyBatis присваивает значение ключа атрибуту индекса Foreach и присваивает значение атрибуту элемента. Здесь целочисленный объект со значением 5 присваивается атрибуту элемента. Следовательно, соответствующий объект, соответствующий атрибуту элемента избранного тега с вставкой в Goaldroomnight30daysmapper.xml, не имеет атрибутов Item.Key и Item.value, что является конечной причиной исключения.
<INSERT ID = "INSERTBATCH" PARAMETERTYPE = "LIST"> Значения into_roomnight_30Days (GOODE_ID, CHECKIN_Room_night_30Days) <foreach Collection = "List" index = "itex =" item ",", ","> ( #{item.key}, #{itex.value}) </for aeach> </ancert> </ancert> </ancert> </ancert> </ancert> </ancert> </ancert> </ancert> </ancert> </ancert> </ancert> </ancert>Выше приведено краткий анализ причин, по которым тег Mybatis Foreach используется неправильно, и я надеюсь, что это будет полезно для вас. Если у вас есть какие -либо вопросы, пожалуйста, оставьте мне сообщение, и редактор ответит вам вовремя. Большое спасибо за вашу поддержку сайту wulin.com!