使用Hibernate+MySql+native SQL的BUG,以及解决办法 ? 使用Hibernate+MySql+native SQL的BUG,以及解决办法 ? 转载自 http://blog.csdn.net/exsuns/article/details/5264125 ? 本来是mssql+hibernate+native SQL 应用的很和谐 但是到了把mssql换成mysql,就出
使用Hibernate+MySql+native SQL的BUG,以及解决办法
?
使用Hibernate+MySql+native SQL的BUG,以及解决办法
?
转载自 http://blog.csdn.net/exsuns/article/details/5264125
?
本来是mssql+hibernate+native SQL 应用的很和谐
但是到了把mssql换成mysql,就出了错(同样的数据结构和数据)。
?
查询方法是:
[java] view plaincopy
- String?sql?=???
- "select?id?XXX_ID??from?t_tab";??
- List
- .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)??
- .list();??
?
错误信息:
[css] view plaincopy
- org.hibernate.exception.SQLGrammarException:?could?not?execute?query??
- ????at?org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90)??
- ????at?org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)??
- ????at?org.hibernate.loader.Loader.doList(Loader.java:2231)??
- ????at?org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)??
- ????at?org.hibernate.loader.Loader.list(Loader.java:2120)??
- ????at?org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:312)??
- ????at?org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1722)??
- ????at?org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:165)??
- ????at?org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:175)??
- ????at?com.exsun.common.dao.BasDaoImpl.findBySql(BasDaoImpl.java:173)??
- ????at?com.exsun.arms.service.EmployeesalaryService.getList(EmployeesalaryService.java:32)??
- ????at?com.exsun.arms.service.EmployeesalaryService$$FastClassByCGLIB$$2d81000f.invoke()??
- ????at?net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)??
- ????at?org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)??
- ????at?org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)??
- ????at?org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)??
- ????at?org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)??
- ????at?org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)??
- ????at?org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)??
- ????at?org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)??
- ????at?com.exsun.arms.service.EmployeesalaryService$$EnhancerByCGLIB$$1e3e6d9f.getList()??
- ????at?com.exsun.arms.action.EmployeesalaryAction.getList(EmployeesalaryAction.java:110)??
- ????at?sun.reflect.NativeMethodAccessorImpl.invoke0(Native?Method)??
- ????at?sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)??
- ????at?sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)??
- ????at?java.lang.reflect.Method.invoke(Method.java:597)??
- ????at?org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:269)??
- ????at?org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:170)??
- ????at?org.springframework.web.struts.DelegatingActionProxy.execute(DelegatingActionProxy.java:110)??
- ????at?org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)??
- ????at?org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)??
- ????at?org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)??
- ????at?org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)??
- ????at?org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:305)??
- ????at?org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)??
- ????at?org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)??
- ????at?org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)??
- ????at?org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)??
- ????at?javax.servlet.http.HttpServlet.service(HttpServlet.java:627)??
- ????at?javax.servlet.http.HttpServlet.service(HttpServlet.java:729)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)??
- ????at?org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)??
- ????at?org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)??
- ????at?com.exsun.common.util.MenuFilter.doFilter(MenuFilter.java:103)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)??
- ????at?org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)??
- ????at?org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)??
- ????at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)??
- ????at?org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)??
- ????at?org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)??
- ????at?org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)??
- ????at?org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)??
- ????at?org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)??
- ????at?org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)??
- ????at?org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:873)??
- ????at?org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)??
- ????at?org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)??
- ????at?org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)??
- ????at?org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)??
- ????at?java.lang.Thread.run(Thread.java:619)??
- Caused?by:?java.sql.SQLException:?Column?'id'?not?found.??
- ????at?com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1072)??
- ????at?com.mysql.jdbc.SQLError.createSQLException(SQLError.java:986)??
- ????at?com.mysql.jdbc.SQLError.createSQLException(SQLError.java:981)??
- ????at?com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)??
- ????at?com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1144)??
- ????at?com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5616)??
- ????at?org.hibernate.type.StringType.get(StringType.java:41)??
- ????at?org.hibernate.type.NullableType.nullSafeGet(NullableType.java:184)??
- ????at?org.hibernate.type.NullableType.nullSafeGet(NullableType.java:210)??
- ????at?org.hibernate.loader.custom.CustomLoader$ScalarResultColumnProcessor.extract(CustomLoader.java:497)??
- ????at?org.hibernate.loader.custom.CustomLoader$ResultRowProcessor.buildResultRow(CustomLoader.java:443)??
- ????at?org.hibernate.loader.custom.CustomLoader.getResultColumnOrRow(CustomLoader.java:340)??
- ????at?org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:629)??
- ????at?org.hibernate.loader.Loader.doQuery(Loader.java:724)??
- ????at?org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)??
- ????at?org.hibernate.loader.Loader.doList(Loader.java:2228)??
- ????...?62?more??
?
?
看到最后Caused by: java.sql.SQLException:
所以我试试用JDBC连接
[java] view plaincopy
- public?class?TestMySqlJDBC?{??
- ????public?static?void?main(String[]?args)?throws?Exception,?IllegalAccessException,?ClassNotFoundException?{??
- ????????Class.forName("com.mysql.jdbc.Driver").newInstance();??
- ???????????Connection?con=java.sql.DriverManager.getConnection("jdbc:mysql://localhost:3306/arms?useUnicode=true&characterEncoding=utf8&","root","");??
- ???????????Statement?stmt=con.createStatement();??
- ????????????ResultSet?rs=stmt.executeQuery("select?id?XXX_ID,name??from?t_tab");??
- ????????????while(rs.next())??
- ????????????{??
- ???????????????System.out.printf("id:%s___name:%s/n",rs.getString("XXX_ID"),rs.getString("name"));??
- ????????????}??
- ????????????rs.close();??
- ????????????stmt.close();??
- ????????????con.close();??
- ????}??
- }??
?
可以很正常的运行。
?
?
后来仔细又看了一下hibernate的执行错误
Caused by: java.sql.SQLException: Column 'id' not found.
是ID 找不到 不是XXX_ID 找不到。这意思貌似hibernate就没按别名alias 来取值
跟踪了一下hibernate
其中在Customer里发现的这一段
?
[java] view plaincopy
- public?class?ScalarResultColumnProcessor?implements?ResultColumnProcessor?{??
- ????????private?int?position?=?-1;??
- ????????private?String?alias;??
- ????????private?Type?type;??
- ????????public?ScalarResultColumnProcessor(int?position)?{??
- ????????????this.position?=?position;??
- ????????}??
- ????????public?ScalarResultColumnProcessor(String?alias,?Type?type)?{??
- ????????????this.alias?=?alias;??
- ????????????this.type?=?type;??
- ????????}??
- ???
- ??????????
- ????????public?Object?extract(??
- ????????????????Object[]?data,??
- ????????????????ResultSet?resultSet,??
- ????????????????SessionImplementor?session)?throws?SQLException,?HibernateException?{??
- ????????????return?type.nullSafeGet(?resultSet,?alias,?session,?null?);??
- ????????}??
- ...........??
- ...........??
- ...........??
hibernate是按照select id,name from tab来解释
而不是 select id XXX_ID , name from tab
这里跟到的数据果然是Hibernate把alias给忽略了。。。
?
?
?
-------------------------------------
继续跟踪hibernate代码.根据调用栈,单步跟踪很快找到
org.hibernate.loader.custom.CustomLoader$ScalarResultColumnProcessor 里面的
?
[java] view plaincopy
- public?void?performDiscovery(Metadata?metadata,?List?types,?List?aliases)?throws?SQLException?{??
- ????????????if?(?alias?==?null?)?{??
- ????????????????alias?=?metadata.getColumnName(?position?);??
- ????????????}??
- ????????????else?if?(?position?0?)?{??
- ????????????????position?=?metadata.resolveColumnPosition(?alias?);??
- ????????????}??
- ????????????if?(?type?==?null?)?{??
- ????????????????type?=?metadata.getHibernateType(?position?);??
- ????????????}??
- ????????????types.add(?type?);??
- ????????????aliases.add(?alias?);??
- ????????}??
?
这里就是拼装将来要根据列名get出来的结果的地方
alias = metadata.getColumnName( position )
getColumnName 跟进去就是JDBC的实现.
跟踪可以看到.从这里get出来的alias不是真正的aliasName,而是originalColumnName原始列名.
?
后来试着修改了hibernate各种方言的设置:MySQLDialect,MySQL5Dialect,MySQL5InnoDBDialect等等还是不行。
?
我用JDBC试了下
mysql-connector-java-5.1.9-bin.jar
mysql-connector-java-5.1.10-bin.jar
mysql-connector-java-5.1.11-bin.jar
?
[java] view plaincopy
- ResultSet?rs=stmt.executeQuery(sql);??
- ????????????ResultSetMetaData?rsmd?=?rs.getMetaData();??
- ????????????int?columnCount?=?rsmd.getColumnCount();??
- ????????????List?columnName?=?new?ArrayList();??
- ????????????for?(int?i?=?1;?i?
- ????????????????String?tmp?=?rsmd.getColumnName(i)?+?"___"?+?rsmd.getColumnLabel(i);??
- ????????????????System.out.println(tmp);??
- }??
三个实现,结果都是一样的.
?
mysql的JDBC要获取alias只能用getColumnLable,不能用getColumnName
而Hibernate取字段名称的时候就只用 getColumnName.
解决办法有两个,一个是改hibernate,再不就得改mysql.
怕Hibernate对别的数据库实现有影响
所以就拿mysql的JDBC驱动开刀了.
把com.mysql.jdbc.ResultSetMetaData
中的
?
[java] view plaincopy
- public?String?getColumnName(int?column)?throws?SQLException?{??
- ????????if?(this.useOldAliasBehavior)?{??
- ????????????return?getField(column).getName();??
- ????}??
- ????????String?name?=?getField(column).getNameNoAliases();??
- ??????????
- ????????if?(name?!=?null?&&?name.length()?==?0)?{??
- ????????????return?getField(column).getName();??
- ????????}??
- ??????????
- ????????return?name;??
- ????}??
修改为:
?
[java] view plaincopy
- public?String?getColumnName(int?column)?throws?SQLException?{??
- ????????return?getColumnLable(column);??
- ????}??
?
然后把JDBC重新打包一下
?
再运行就OK了.
最佳解决方法:
?
在jdbc.url中追加mysql参数 &useOldAliasMetadataBehavior=true 就可以解决。
if (this.useOldAliasBehavior) {
return getField(column).getName();
}
?
?