使用Hibernate+MySql+native SQL的BUG,以及解決辦法
本來是mssql+hibernate+native SQL 應用的很和諧
但是到了把mssql換成mysql,就出了錯(同樣的資料結構和資料)。
查詢方法是:
- String sql =
- "select id XXX_ID from t_tab";
- List
- .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(
) - 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連線
- 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
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了.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/90618/viewspace-776511/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 使用Hibernate+MySql+nativeSQL的BUG,以及解決辦法MySql
- WebBrowser隱藏後自動銷燬的BUG以及解決辦法 (轉)Web
- Spark on mesos的坑以及解決辦法Spark
- Hive常見的bug與解決辦法。Hive
- Oracle死鎖的檢視以及解決辦法Oracle
- rootkits病毒的原理介紹以及解決辦法
- Dumpzilla工具第615行bug的解決辦法
- 在使用SwipebackLayout出現的bug以及解決的方法
- 【轉】JS浮點數運算Bug的解決辦法JS
- 連線sql server時,不能使用127.0.0.1的解決辦法SQLServer127.0.0.1
- ScrollView巢狀ListView解決辦法以及原理View巢狀
- Mybatis批量更新SQL報錯☞解決辦法MyBatisSQL
- 哈哈,PHP中使用foreach和引用導致程式BUG及解決辦法PHP
- .Net Core3.1中SameSite的使用方法、遇到的問題以及解決辦法
- 你遇到過的相容性問題以及解決辦法
- 解決非root使用者使用docker的辦法Docker
- IE6中的常見BUG與相應的解決辦法
- 使用者被鎖解決辦法
- npm 使用安裝超時的解決辦法NPM
- Authentication failure 以及xxx is not in the sudoers file 問題的解決辦法AI
- handlder引起的記憶體洩漏問題以及解決辦法記憶體
- 讓div等塊級元素水平以及垂直居中的解決辦法
- WSL中配置EDA環境:遇到的問題以及解決辦法
- Homestead 12.1.0 + VsCode Xdebug不生效的解決辦法VSCode
- bugzilla更新出現perl模組無法安裝問題解決辦法
- OpenStack 的NAT解決辦法
- 公寓噪音的解決辦法
- This function has none of DETEMINISTIC,NO SQL錯誤解決辦法FunctionNoneSQL
- PL/SQL Developer-中文註釋亂碼的解決辦法SQLDeveloper
- 普通使用者SSH無密碼互信建立 出現的問題以及解決辦法密碼
- 64位機器上使用PL/SQL Developer 連線不上Oracle的解決辦法SQLDeveloperOracle
- 過擬合和欠擬合以及相對應的解決辦法
- MySQL組複製的幾個常見問題以及解決辦法MySql
- JavaMail的com/sun/mail/util/LineInputStream錯誤 以及解決辦法JavaAI
- IE CSS Bug系列:IE6中Min-Height的解決辦法CSS
- [BUG反饋]onethink自帶的kindeditor遮蔽dl,dt,dd的解決辦法
- SQL SERVER 資料庫被標記為“可疑”的解決辦法SQLServer資料庫
- SQL SERVER 2005服務無法啟動問題的解決辦法SQLServer