Cenário de geração de exceção e informações de exceção
Na semana passada, ocorreu uma exceção porque a classe genérica que implementa a interface do mapa. A seguir, são as informações de exceção:
org.apache.ibatis.exceptions.persistenceException: ### Erro atualizando o banco de dados. Causa: org.apache.ibatis.reflection.ReflectionException: Não há getter para propriedade denominada 'chave' na classe java.lang.integer '### o erro pode envolver org.guojing.test.spring.server.GoodSroom30Daysmapper.InsertBs-nline ##MineRen the Errlerroom30Daysmapper.insertBin-inline bens_roomnight_30days (bens_id, checkin_room_night_30days) valores (?,?), (?,?), (?,?), (?,?), (?,?) ### Causa: org.apache.ibatis.reflection.reflectionException: não é para a propriedade 'key' em 'na classe' java. org.apache.ibatis.exceptions.exceptionFactory.wrapexception (excepcionactory.java:30) em org.apache.ibatis.session.defaults.defaultsqlsession.update (defaultsqlsess.java:200) em org.apache.ibatis.session.defaults.defaultsqlsession.insert (defaultsqlsession.java:185) em org.apache.ibatis.binding.mappermethod.execute (mappermethod.java:57) em org.apache.ibatis.binding.mapperProxy.invoke (mapperproxy.java:53) em com.sun.proxy. $ proxy4.insertbatch (fonte desconhecida) em org.guojing.test.spring.server.godsroomnightnight.4stest.guojing.test.Pring.Server.GoodsOngenAnkAddaystest.Test.Test.TestSest (BOTHERSOLTILLEGNOUSTNOWLIGHTNOWLY30). sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.method.invoke (method.java:606) em org.junit.runners.model.frameworkmethod $ 1.runreflectiveCall (arcrameworkmethod.java:47) em org.junit.internal.runners.model.reflectiveCallable.run (refleteCallable.java:12) em org.junit.runners.model.frameworkmethod.invokeexplosive (frameworkmethod.java:44) em org.junit.internal.runners.statements.invokemethod.Evaluate (Invokemethod.java:17) em org.junit.internal.runners.statements.runbefores.valuate (runbefores.java:26) em org.junit.internal.runners.statements.runafters.evaluate (runafters.java:27) em org.junit.runners.parentrunner.runleaf (parentrunner.java:271) em org.junit.runners.blockJunit4ClassRunner.Runchild (blockjunit4classrunner.java:70) em org.junit.runners.blockjunit4classrunner.runchild (blockjunit4classrunner.java:50) em org.junit.runners.parentrunner $ 3.run (parardrunner.java:238) em org.junit.runners.parentrunner $ 1.Schedule (parentRunner.java:63) em org.junit.runners.arentrunner.runchdren (parentrunner3) org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.junit.runner.junitcore.run (junitcore.java:160) em com.intellij.junit4 com.Intellij.rt.execution.junit.idereatestrunner $ repetidor.startrunnerwithargs (ideatestrunner.java:51) em com.intellij.rt.execution.junit.junitstarter.prestreamsAndStart (junitstarter.junit. com.Intellij.rt.execution.junit.junitstarter.main (junitstarter.java:70) causado por: org.apache.ibatis.reflection.reflectionException: não há um getter para a propriedade denominada 'chave' na classe java.lang.integer 'em org.apache.ibatis.reflection.Reflector.getGetInvoker(Reflector.java:409) at org.apache.ibatis.reflection.MetaClass.getGetInvoker(MetaClass.java:164) at org.apache.ibatis.reflection.wrapper.BeanWrapper.getBeanProperty(BeanWrapper.java:162) em org.apache.ibatis.reflection.wrapper.beanwrapper.get (beanwrapper.java:49) em org.apache.ibatis.reflection.metaObject.getValue (metaobject.java:122) at org.apache.ibensev.reflection.metaBject.MetaBject.TaBject.Java:122) em org.apache.Abjectis.reflection.metaBject.metAbjuck org.apache.ibatis.mapping.boundsql.getAdditionalParameter (boundsql.java:75) em org.apache.ibatis.scripting.defaults.defaultParameterHandler.setParameters (defaultParameterHandler.java:72) AT org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize (preparadostatementHandler.java:93) em org.apache.ibatis.executor.statement.routtingStatementHandler.parameteriz org.apache.ibatis.executor.simpleExecutor.Preparestatement (SimpleExecutor.java:86) em org.apache.ibatis.executor.simpleexecutor.doupdate (simplexecutor.java:49) emor.apeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeMeeMeeMeeMeeMeeMeeMeeMeeMexeTecut.Java.Java:49) em org.apache.ibatis.session.defaults.defaultsqlsession.update (padrãosqlsession.java:198) ... 29 mais
Como não sei muito sobre Mybatis, demorei muito tempo para depurar e descobrir a causa específica da anormalidade.
Em seguida, reproduzirei a exceção e analisarei as causas da exceção.
A exceção reaparece
Para reproduzir a exceção acima, uma demonstração foi escrita. Os códigos relevantes são os seguintes:
Estrutura da tabela de banco de dados:
Criar tabela `bens_roomnight_30Days` (` bens_id` bigint (20) não nulo, `checkin_room_night_30days` int (11) não nulo padrão '0' comentário 'Última noite de 30 dias', chave primária (` bens_id`)) mecanismo = innod default charset = utf8 comentário = 'bens' 30 dias
Classe de parâmetro keyvalue.java:
classe pública keyvalue <k, v> implementa mapa.entry <k, v> {private k key; Valor V Privado; public KeyValue () {} public KeyValue (K Key, V Value) {this.key = key; this.value = value; } @Override public k getKey () {return Key; } @Override public v getValue () {return value; } @Override public v setTalue (V Valor) {v OldValue = this.value; this.value = value; retornar OldValue; } public jsonObject tojsonObject () {return reportjsonObject.NewObject (). Append (string.valueof (key), value); } @Override public string tostring () {return toJsonObject (). TojSonstring (); }}DAO CLASSOMOUNGONGENDIGHT30DAYSMAPPER.JAVA
Public Interface Goodsroomnight30DaysMapper {int DeLeteByExample (Exemplo de Bensroomize30DaySexample); Lista <Goodsroomnight30Days> SelectByExample (Exemplo de Bensroom30Daysexample); <K, v> int insertbatch (list <keyvalue <k, v >> registros);}arquivo mybatis-config.xml:
<?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"/> </configurações> <!-Após a integração com a primavera, a configuração dos ambientes será abolida e entregue ao gerenciamento da mola-> <ambientes default = "Development"> <ambiente id = "Development"> <!-Use JDBC Management de transação-> <transação type = "jdbc"/> <!-DATATASE Ponectase-> type = "pooled"> <propriedade name = "driver" value = "com.mysql.jdbc.driver" /> <names name = "url" value = "jdbc: mysql: // locicalHost: 3306 /hotel_report? caracterencoding = utf-8" /> <nome da propriedade = "username" value = " </datasource> </ambiente> </ambientes> <pampers> <mapper Resource = "mybatis/bensroomnight30daysmapper.xml"/> </pperpers> </figuration>
O principal conteúdo da sala de mercadorias noite30Daysmapper.xml arquivo:
<insert id = "insertbatch" parametertype = "list"> substituir em bens_roomnight_30days (bens_id, checkin_room_night_30days) null "> (#{item.key}, 0) </when>-> <!-<quando test =" item.value! = null "> (#{item.key},#{item.value}) </when>-> <!-</escolha>-> </foreach> </nsert>O acima é o código principal para reproduzir esta exceção. O código completo pode ser visualizado no Github: https://github.com/misterzhou/java-demo/tree/master/test-spring/spring-severver
Código de teste que reproduz a exceção da sala de mercadorias 30Daystest.java:
pacote org.guojing.test.spring.server; importar org.apache.ibatis.io.resources; importar org.apache.ibatis.session.sqlSession; importação org.apache.session.Session.SessionFactory; importação org.apache.ibatis.sesql; org.apache.ibatis.session.sqlSessionFactoryBuilder; importar org.guojing.spring.commons.keyvalue; importar org.junit.after; importar org.junit.before; java.util.list;/** * Criado em: 2016-12-24 * * @author guojing */public class Roomnight 30Daystest {sqlSessionFactory sqlSessionFactory; SQLSession SQLSession; ROOD NOATENDIDA30DAYSMAPPEROMONGNOMNIGHT30DAYSMAPPER; @Before public void init () lança IoException {String Resource = "mybatis/mybatis-config.xml"; InputStream inputStream = Resources.GetResourCeasStream (Resource); sqlSessionFactory = new SQLSessionFactoryBuilder (). Build (InputStream); sqlSession = sqlSessionFactory.opensssion (true); bensroomnight30daysmapper = sqlsession.getmapper (bensroomnight30Daysmapper.class); } @Test public void test () {list <KeyValue <Long, Integer >> registros = new ArrayList <> (); registros. registros.add (novo KeyValue <Long, Integer> (1728L, 3)); registros.add (novo KeyValue <Long, Integer> (1730L, NULL)); registros.add (novo KeyValue <Long, Integer> (1758L, NULL)); Int Deleted = Goodsroomnight30DaysMapper.DeleteByExample (New Goodsroomnight30DaySexample ()); System.out.println ("----- Tamanho da linha excluído:" + excluído); Int Row = Goodsroomnight30Daysmapper.insertBatch (Records); System.out.println ("----- Rinha afetada:" + linha); Lista <Goodsroomnight30Days> Result = BOTSOLONGENHANTE30DAYSMAPPER.SELECTBYEXAMPLE (NOVA BOTSOONGENNOTH30DaySexample ()); para (BOTSOLOWNOTKN30DAYS ITEM: Result) {System.out.println (item.toString ()); }} @After public void depois () {if (sqlSession! = Null) {sqlSession.close (); }}}Vamos mantê -lo em segredo, não olhe para baixo primeiro, pense nas causas da anormalidade (os alunos que são proficientes no uso da etiqueta foreach devem poder ver as pistas).
Processo de exceção e análise de exceção
No projeto, como a classe de parâmetros e a classe de resultado de retorno do método DAO geralmente contêm um valor correspondente à chave e à chave, a fim de evitar definir repetidamente a classe, defini uma classe genérica KeyValue que implementa a interface do mapa.Entry. Para detalhes, consulte a seção anterior.
GoodsRoomnight30daysMapper.insertBatch() usa esta classe genérica. Após a execução, as informações de exceção mencionadas no início deste artigo são lançadas.
Depois de ver as informações de exceção, concentrei -me em saber se o apoio da Mybatis aos genéricos não é bom o suficiente. Perguntei ao meu colega (@shengnan), e meu colega experimentou em sua máquina e descobriu que não havia anormalidade. Isso é estranho. Após uma olhada mais detalhada do código, descobri que a diferença é que minha classe genérica KeyValue implementa o mapa.entry Interface. No momento, não conheço a descrição da tag foreach no site oficial do Mybatis:
Qualquer objeto iterável (como listas, coleções, etc.) e qualquer objeto de dicionário ou matriz pode ser passado para o foreach como parâmetros de coleta. Ao usar um objeto ou matriz iterável, o índice é o número de vezes iterado e o valor do item é o elemento obtido nesta iteração. Ao usar um dicionário (ou uma coleção de objetos map.entry), o índice é a chave e o item é o valor.
Em seguida, verifique os motivos específicos da exceção por meio de depuração. Então eu usei o código da classe KeyValue que implementa o mapa.Entry Interface para depurar. Através do log de exceção, posso ver que a exceção é lançada na linha defaultSqlSession.java:200, então eu bati no ponto de interrupção para linha padrãosqlsession.java:197 e depois o executei passo a passo. Quando o executei para alinhar foreachsqlnode.java:73, finalmente percebi. Vamos dar uma olhada no diagrama de cadeias de chamadas de depuração primeiro:
Vamos dar uma olhada no código específico paraeachsqlnode.java:73 (esta classe é a classe de nó do objeto de tag foreach):
Neste momento, a causa específica da exceção é muito óbvia. A classe à qual o objeto O aqui pertence é a classe KeyValue. Como a classe KeyValue implementa a interface map.entry, o mapa de instância. Aqui, o objeto inteiro com um valor de 5 é atribuído ao atributo do item. Portanto, o objeto correspondente correspondente ao atributo do item da tag de seleção com insertbatch no bodyroomnight30Daysmapper.xml não possui os atributos item.Key e Item.Value, que é a causa final da exceção.
<inserir id = "insertbatch" parametertype = "list"> substituir em bens_roomnight_30days (bens_id, checkin_room_night_30days)
O exposto acima é uma breve análise das razões pelas quais a tag mybatis foreach é usada indevidamente, e espero que seja útil para você. Se você tiver alguma dúvida, deixe -me uma mensagem e o editor responderá a você a tempo. Muito obrigado pelo seu apoio ao site wulin.com!