最近在一个Hibernater的项目中遇到了一个这样的问题,执行下边的代码会报出一个IllegalArgumentException的异常
//这样子写会报IllegalArgumentException异常。 public List<Commodity> getByPlate(String plateId,int count) { String hql = "select c from Commodity c where c.enjoinPlate =:plateId"; return sf.getCurrentSession().createQuery(hql) .setParameter("plateId",plateId) .setFirstResult(0) .setMaxResults(count) .list(); } //如果换成这样子写的话,就能正常工作 public List<Commodity> getByPlate(String plateId,int count) { String hql = "select c from Commodity c where c.enjoinPlate ='" + plateId + "''; return sf.getCurrentSession().createQuery(hql) .setFirstResult(0) .setMaxResults(count) .list(); }
异常如下:
三月 23, 2014 10:33:27 上午 org.apache.catalina.core.StandardWrapperValve invoke SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/NetMall] threw exception [Request processing failed; nested exception is org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.line.web.model.Plate.id] with root cause java.lang.IllegalArgumentException: java.lang.ClassCastException@17c753a at sun.reflect.GeneratedMethodAccessor33.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:164) at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:341) at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4425) at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4147) at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:209) at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:248) at org.hibernate.type.EntityType.getIdentifier(EntityType.java:459) at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:141) at org.hibernate.param.NamedParameterSpecification.bind(NamedParameterSpecification.java:66) at org.hibernate.loader.hql.QueryLoader.bindParameterValues(QueryLoader.java:588) at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1736) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1697) at org.hibernate.loader.Loader.doQuery(Loader.java:832) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:293) at org.hibernate.loader.Loader.doList(Loader.java:2382) at org.hibernate.loader.Loader.doList(Loader.java:2368) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2198) at org.hibernate.loader.Loader.list(Loader.java:2193) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:195) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1244) at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101) at com.line.web.model.dao.CommodityDaoImpl.getByPlate(CommodityDaoImpl.java:45) at com.line.web.service.PlateServiceImpl.getPopularCommodity(PlateServiceImpl.java:149) at 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) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) at com.sun.proxy.$Proxy27.getPopularCommodity(Unknown Source) at com.line.web.controller.PlateController.showSecondPlate(PlateController.java:28) at 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) at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778) at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:724)
下面是我的表
@Entity @Table(name="commodity") public class Commodity { private String id; //商品名 private String name; //价格 private double price; //库存 private int stock; //销量 private int sales; //图片 private String image; //描述 private String description; //所属商店 private Shop enjoinShop; //所属板块 private Plate enjoinPlate; /** getter and setter*/ } @Entity @Table(name="plate") public class Plate { private String id; private String name; private int level; private int showSeq; private List<Plate> childPlate; private Plate parentPlate; }
这个问题纠结了我好久,我在其他的表中也有用setParameter()方法,当其他的表也能正常工作,为什么这个不能。由回头去仔细看了一下异常,首先是Plate 表的 id get()方法出错了,然后也提示有ClassCastException,证明类型匹配错误,我又回头去看了一下Plate表的id定义,确实是String类型啊。这部分应该没问题,然后继续看下异常栈。
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:164) at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:341) at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4425) at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4147) at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:209) at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:248) at org.hibernate.type.EntityType.getIdentifier(EntityType.java:459) //获得主键 at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:141) at org.hibernate.param.NamedParameterSpecification.bind(NamedParameterSpecification.java:66) //查找参数值 at org.hibernate.loader.hql.QueryLoader.bindParameterValues(QueryLoader.java:588) //绑定参数 at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1736) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1697) at org.hibernate.loader.Loader.doQuery(Loader.java:832) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:293) at org.hibernate.loader.Loader.doList(Loader.java:2382) at org.hibernate.loader.Loader.doList(Loader.java:2368) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2198) at org.hibernate.loader.Loader.list(Loader.java:2193) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:195) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1244) at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101) //执行Query的List方法
从获得主键那里我们就可以看出了,这里是有问题,我们Query语句传入的参数是String类型的plateId,而根据异常栈我们能看出,它是通过反射,将我们的参数当成了一个Plate类型并试图通过getId()方法去获得外键的值,所以在由String转Plate过程中就出现了ClassCastException异常了。所以我们正确写法应该是这样子的
@Override public List<Commodity> getByPlate(Plate plate,int count) { String hql = "select c from Commodity c where c.enjoinPlate =:plate"; return sf.getCurrentSession().createQuery(hql) .setParameter("plate",plate) //这里传入的应该是Plate对象。 .setFirstResult(0) .setMaxResults(count) .list(); }
这个错误刚出现的时候我用Google搜了一下,貌似相同问题的并不多,应为这个发生在由于Hibernate框架本来就是为了我们像操作对象一样的去操作我们的关系型数据库,而我犯的错误正是以关系型数据库为基础去写的查询语句,所以就存在两者间匹配出错的问题,而采用拼接字符串的做法没有出错我想是因为少了参数的绑定的过程,不过感觉还是不要那么写比较好,因为那样一半用对象的方式写查询语句,一半用基础SQL语句的类型来写查询语句,有种四不像的感觉。
参考资料:https://community.jboss.org/thread/27095?start=0&tstart=0&_sscc=t