使用Hibernate+MySql+native SQL的BUG,以及解决办法
2010-01-28 09:40
519 查看
本来是mssql+hibernate+native SQL 应用的很和谐
但是到了把mssql换成mysql,就出了错(同样的数据结构和数据)。
查询方法是:
错误信息:
看到最后Caused by: java.sql.SQLException:
所以我试试用JDBC连接
可以很正常的运行。
后来仔细又看了一下hibernate的执行错误
Caused by: java.sql.SQLException: Column 'id' not found.
是ID
找不到 不是XXX_ID
找不到。这意思貌似hibernate就没按别名alias
来取值
跟踪了一下hibernate
其中在Customer里发现的这一段
hibernate是按照select id,name from tab来解释
而不是
select id
XXX_ID
, name from tab
这里跟到的数据果然是Hibernate把alias给忽略了。。。
-------------------------------------
继续跟踪hibernate代码.根据调用栈,单步跟踪很快找到
org.hibernate.loader.custom.CustomLoader$ScalarResultColumnProcessor 里面的
这里就是拼装将来要根据列名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
三个实现,结果都是一样的.
mysql的JDBC要获取alias只能用getColumnLable,不能用getColumnName
而Hibernate取字段名称的时候就只用
getColumnName.
解决办法有两个,一个是改hibernate,再不就得改mysql.
怕Hibernate对别的数据库实现有影响
所以就拿mysql的JDBC驱动开刀了.
把com.mysql.jdbc.ResultSetMetaData
中的
修改为:
然后把JDBC重新打包一下
再运行就OK了.
但是到了把mssql换成mysql,就出了错(同样的数据结构和数据)。
查询方法是:
String sql = "select id XXX_ID from t_tab"; List<Map> list = session.createSQLQuery(sql) .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP) .list();
错误信息:
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(<generated>) 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(<generated>) 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连接
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里发现的这一段
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; } //这个方法中的alias 为"id"而不是XXX_ID 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 里面的
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
ResultSet rs=stmt.executeQuery(sql); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); List<String> columnName = new ArrayList(); for (int i = 1; i <= columnCount; 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
中的
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; }
修改为:
public String getColumnName(int column) throws SQLException { return getColumnLable(column); }
然后把JDBC重新打包一下
再运行就OK了.
相关文章推荐
- 使用Hibernate+MySql+native SQL的BUG,以及解决办法
- python2.6使用mysql包出现的一些问题以及解决办法
- hibernate 使用mysql6.0 无法自动建表的解决办法
- Hibernate使用原生SQL多表查询时字段名相同导致查询数据覆盖问题解决办法
- Mysql 使用ibd数据文件进行数据恢复 (以及数据移动) 1067的解决办法
- hibernate使用原生sql查询Hibernate原生SQL多表查询字段名重复问题以及解决方法
- 使用hibernate与mysql时数据不能插入的原因及解决办法
- Java使用jdbc链接数据库的MySQL 5.5.45+以及SSL错误解决办法
- 当Dao层继承了HibernateDaoSupport,使用底层SQL语句,session获取的方法,以及解决关联查询no session的问题
- python2.6使用mysql包出现的一些问题以及解决办法
- Hibernate数据的lazy问题,以及使用spring整合hibernate lazy的解决办法(好文转载)
- Hibernate 使用 SQL 查询时报错 “对象名 XX 无效”的解决办法
- 使用Hibernate 5.0、4.0、3.0 createSQLQuery执行原生Sql语句 遇到问题及解决办法集锦
- 使用eclipse连接mysql database explorer连接不上的解决办法以及配置
- Hibernate 使用 SQL 查询时报错 “对象名 XX 无效”的解决办法
- Coolpy使用注意事项以及常见问题解决办法(持续更新中)
- mysql存储过程中不能使用return的解决办法
- hibernate使用hql跨表查询遇到的问题以及解决方式
- Solaris 下安装Perl的DBD-mysql模块失败的原因以及解决办法
- mysql导入sql文件报错,“This function has none of DETERMINISTIC”,解决办法