使用Hibernate+MySql+native SQL的BUG,以及解决办法

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
应用实时监控服务-应用监控,每月50GB免费额度
简介:   本来是mssql+hibernate+native SQL 应用的很和谐 但是到了把mssql换成mysql,就出了错(同样的数据结构和数据)。   查询方法是:   [java] view plaincopy   String sq...
 

 

本来是mssql+hibernate+native SQL 应用的很和谐

但是到了把mssql换成mysql,就出了错(同样的数据结构和数据)。

 

查询方法是:

 

[java]  view plain copy
 
  1. String sql =   
  2. "select id XXX_ID  from t_tab";  
  3. List<Map> list = session.createSQLQuery(sql)  
  4. .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)  
  5. .list();  

 

 

 

错误信息:

 

[css]  view plain copy
 
  1. org.hibernate.exception.SQLGrammarException: could not execute query  
  2.     at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90)  
  3.     at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)  
  4.     at org.hibernate.loader.Loader.doList(Loader.java:2231)  
  5.     at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)  
  6.     at org.hibernate.loader.Loader.list(Loader.java:2120)  
  7.     at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:312)  
  8.     at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1722)  
  9.     at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:165)  
  10.     at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:175)  
  11.     at com.exsun.common.dao.BasDaoImpl.findBySql(BasDaoImpl.java:173)  
  12.     at com.exsun.arms.service.EmployeesalaryService.getList(EmployeesalaryService.java:32)  
  13.     at com.exsun.arms.service.EmployeesalaryService$$FastClassByCGLIB$$2d81000f.invoke(<generated>)  
  14.     at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)  
  15.     at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)  
  16.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)  
  17.     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)  
  18.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)  
  19.     at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)  
  20.     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)  
  21.     at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)  
  22.     at com.exsun.arms.service.EmployeesalaryService$$EnhancerByCGLIB$$1e3e6d9f.getList(<generated>)  
  23.     at com.exsun.arms.action.EmployeesalaryAction.getList(EmployeesalaryAction.java:110)  
  24.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
  25.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
  26.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
  27.     at java.lang.reflect.Method.invoke(Method.java:597)  
  28.     at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:269)  
  29.     at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:170)  
  30.     at org.springframework.web.struts.DelegatingActionProxy.execute(DelegatingActionProxy.java:110)  
  31.     at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)  
  32.     at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)  
  33.     at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)  
  34.     at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)  
  35.     at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:305)  
  36.     at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)  
  37.     at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)  
  38.     at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)  
  39.     at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)  
  40.     at javax.servlet.http.HttpServlet.service(HttpServlet.java:627)  
  41.     at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)  
  42.     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)  
  43.     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)  
  44.     at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)  
  45.     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)  
  46.     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)  
  47.     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)  
  48.     at com.exsun.common.util.MenuFilter.doFilter(MenuFilter.java:103)  
  49.     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)  
  50.     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)  
  51.     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)  
  52.     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)  
  53.     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)  
  54.     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)  
  55.     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)  
  56.     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)  
  57.     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)  
  58.     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)  
  59.     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)  
  60.     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)  
  61.     at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:873)  
  62.     at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)  
  63.     at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)  
  64.     at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)  
  65.     at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)  
  66.     at java.lang.Thread.run(Thread.java:619)  
  67. Caused by: java.sql.SQLException: Column 'id' not found.  
  68.     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1072)  
  69.     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:986)  
  70.     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:981)  
  71.     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)  
  72.     at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1144)  
  73.     at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5616)  
  74.     at org.hibernate.type.StringType.get(StringType.java:41)  
  75.     at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:184)  
  76.     at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:210)  
  77.     at org.hibernate.loader.custom.CustomLoader$ScalarResultColumnProcessor.extract(CustomLoader.java:497)  
  78.     at org.hibernate.loader.custom.CustomLoader$ResultRowProcessor.buildResultRow(CustomLoader.java:443)  
  79.     at org.hibernate.loader.custom.CustomLoader.getResultColumnOrRow(CustomLoader.java:340)  
  80.     at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:629)  
  81.     at org.hibernate.loader.Loader.doQuery(Loader.java:724)  
  82.     at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)  
  83.     at org.hibernate.loader.Loader.doList(Loader.java:2228)  
  84.     ... 62 more  

 

 

 

看到最后Caused by: java.sql.SQLException:

所以我试试用JDBC连接

 

[java]  view plain copy
 
  1. public class TestMySqlJDBC {  
  2.     public static void main(String[] args) throws Exception, IllegalAccessException, ClassNotFoundException {  
  3.         Class.forName("com.mysql.jdbc.Driver").newInstance();  
  4.            Connection con=java.sql.DriverManager.getConnection("jdbc:mysql://localhost:3306/arms?useUnicode=true&characterEncoding=utf8&","root","");  
  5.            Statement stmt=con.createStatement();  
  6.             ResultSet rs=stmt.executeQuery("select id XXX_ID,name  from t_tab");  
  7.             while(rs.next())  
  8.             {  
  9.                System.out.printf("id:%s___name:%s/n",rs.getString("XXX_ID"),rs.getString("name"));  
  10.             }  
  11.             rs.close();  
  12.             stmt.close();  
  13.             con.close();  
  14.     }  
  15. }  

 

 

可以很正常的运行。

 

 

后来仔细又看了一下hibernate的执行错误

Caused by: java.sql.SQLException: Column 'id' not found.

是ID 找不到 不是XXX_ID 找不到。这意思貌似hibernate就没按别名alias 来取值

跟踪了一下hibernate

其中在Customer里发现的这一段

 

[java]  view plain copy
 
  1. public class ScalarResultColumnProcessor implements ResultColumnProcessor {  
  2.         private int position = -1;  
  3.         private String alias;  
  4.         private Type type;  
  5.         public ScalarResultColumnProcessor(int position) {  
  6.             this.position = position;  
  7.         }  
  8.         public ScalarResultColumnProcessor(String alias, Type type) {  
  9.             this.alias = alias;  
  10.             this.type = type;  
  11.         }  
  12.    
  13.         //这个方法中的alias 为"id"而不是XXX_ID  
  14.         public Object extract(  
  15.                 Object[] data,  
  16.                 ResultSet resultSet,  
  17.                 SessionImplementor session) throws SQLException, HibernateException {  
  18.             return type.nullSafeGet( resultSet, alias, session, null );  
  19.         }  
  20. ...........  
  21. ...........  
  22. ...........  

 

hibernate是按照select id,name from tab来解释

而不是 select id XXX_ID , name from tab

这里跟到的数据果然是Hibernate把alias给忽略了。。。

 

 

 

-------------------------------------

继续跟踪hibernate代码.根据调用栈,单步跟踪很快找到

org.hibernate.loader.custom.CustomLoader$ScalarResultColumnProcessor 里面的

 

[java]  view plain copy
 
  1. public void performDiscovery(Metadata metadata, List types, List aliases) throws SQLException {  
  2.             if ( alias == null ) {  
  3.                 alias = metadata.getColumnName( position );  
  4.             }  
  5.             else if ( position < 0 ) {  
  6.                 position = metadata.resolveColumnPosition( alias );  
  7.             }  
  8.             if ( type == null ) {  
  9.                 type = metadata.getHibernateType( position );  
  10.             }  
  11.             types.add( type );  
  12.             aliases.add( alias );  
  13.         }  

 

 

这里就是拼装将来要根据列名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 plain copy
 
  1. ResultSet rs=stmt.executeQuery(sql);  
  2.             ResultSetMetaData rsmd = rs.getMetaData();  
  3.             int columnCount = rsmd.getColumnCount();  
  4.             List<String> columnName = new ArrayList();  
  5.             for (int i = 1; i <= columnCount; i++) {  
  6.                 String tmp = rsmd.getColumnName(i) + "___" + rsmd.getColumnLabel(i);  
  7.                 System.out.println(tmp);  
  8. }  

 

三个实现,结果都是一样的.

 

mysql的JDBC要获取alias只能用getColumnLable,不能用getColumnName

而Hibernate取字段名称的时候就只用 getColumnName.

解决办法有两个,一个是改hibernate,再不就得改mysql.

怕Hibernate对别的数据库实现有影响

所以就拿mysql的JDBC驱动开刀了.

com.mysql.jdbc.ResultSetMetaData

中的

 

[java]  view plain copy
 
  1. public String getColumnName(int column) throws SQLException {  
  2.         if (this.useOldAliasBehavior) {  
  3.             return getField(column).getName();  
  4.     }  
  5.         String name = getField(column).getNameNoAliases();  
  6.           
  7.         if (name != null && name.length() == 0) {  
  8.             return getField(column).getName();  
  9.         }  
  10.           
  11.         return name;  
  12.     }  

 

修改为:

 

[java]  view plain copy
 
  1. public String getColumnName(int column) throws SQLException {  
  2.         return getColumnLable(column);  
  3.     }  

 

 

然后把JDBC重新打包一下

再运行就OK了.

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
8天前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(01)一条简单SQL搞懂MySQL架构原理 | 含实用命令参数集
本文从MySQL的架构原理出发,详细介绍其SQL查询的全过程,涵盖客户端发起SQL查询、服务端SQL接口、解析器、优化器、存储引擎及日志数据等内容。同时提供了MySQL常用的管理命令参数集,帮助读者深入了解MySQL的技术细节和优化方法。
|
9天前
|
SQL Oracle 关系型数据库
SQL(MySQL)
SQL语言是指结构化查询语言,是一门ANSI的标准计算机语言,用来访问和操作数据库。 数据库包括SQL server,MySQL和Oracle。(语法大致相同) 创建数据库指令:CRATE DATABASE websecurity; 查看数据库:show datebase; 切换数据库:USE websecurity; 删除数据库:DROP DATABASE websecurity;
|
2月前
|
SQL 运维 关系型数据库
MySQL 运维 SQL 备忘
MySQL 运维 SQL 备忘录
48 1
|
1月前
|
SQL 关系型数据库 MySQL
MySql5.6版本开启慢SQL功能-本次采用永久生效方式
MySql5.6版本开启慢SQL功能-本次采用永久生效方式
41 0
|
1月前
|
SQL 关系型数据库 MySQL
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
31 0
|
7月前
|
SQL 缓存 Java
框架分析(9)-Hibernate
框架分析(9)-Hibernate
|
1月前
|
缓存 Java 数据库连接
Hibernate:Java持久层框架的高效应用
通过上述步骤,可以在Java项目中高效应用Hibernate框架,实现对关系数据库的透明持久化管理。Hibernate提供的强大功能和灵活配置,使得开发者能够专注于业务逻辑的实现,而不必过多关注底层数据库操作。
18 1
|
4月前
|
SQL Java 数据库连接
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。通过映射机制,它可以自动处理对象与数据库表之间的转换,支持主流数据库,提高了代码的可移植性和可维护性。其核心接口包括 SessionFactory、Session 和 Transaction 等,通过它们可以执行数据库的 CRUD 操作。配置方面,需在项目中引入 Hibernate 及数据库驱动依赖,并创建 `hibernate.cfg.xml` 配置文件来设置数据库连接和 Hibernate 行为参数。
56 1
|
4月前
|
数据库 Java 数据库连接
Struts 2 与 Hibernate 的完美邂逅:如何无缝集成两大框架,轻松玩转高效 CRUD 操作?
【8月更文挑战第31天】本文通过具体示例介绍了如何在 Struts 2 中整合 Hibernate,实现基本的 CRUD 操作。首先创建 Maven 项目并添加相关依赖,接着配置 Hibernate 并定义实体类及其映射文件。然后创建 DAO 接口及实现类处理数据库操作,再通过 Struts 2 的 Action 类处理用户请求。最后配置 `struts.xml` 文件并创建 JSP 页面展示用户列表及编辑表单。此示例展示了如何配置和使用这两个框架,使代码更加模块化和可维护。
123 0
|
5月前
|
SQL Java 数据库连接
Java面试题:简述ORM框架(如Hibernate、MyBatis)的工作原理及其优缺点。
Java面试题:简述ORM框架(如Hibernate、MyBatis)的工作原理及其优缺点。
87 0