0
点赞
收藏
分享

微信扫一扫

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


 

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

 

 



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

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

 

查询方法是:



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();


 


错误信息:





    1. org.hibernate.exception.SQLGrammarException: could not execute query  
    2. 90)  
    3. 66)  
    4. 2231)  
    5. 2125)  
    6. 2120)  
    7. 312)  
    8. 1722)  
    9. 165)  
    10. 175)  
    11. 173)  
    12. 32)  
    13. 2d81000f.invoke(<generated>)  
    14. 149)  
    15. 2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)  
    16. 149)  
    17. 106)  
    18. 171)  
    19. 89)  
    20. 171)  
    21. 2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)  
    22. 1e3e6d9f.getList(<generated>)  
    23. 110)  
    24. 0(Native Method)  
    25. 39)  
    26. 25)  
    27. 597)  
    28. 269)  
    29. 170)  
    30. 110)  
    31. 58)  
    32. 67)  
    33. 51)  
    34. 191)  
    35. 305)  
    36. 191)  
    37. 283)  
    38. 1913)  
    39. 449)  
    40. 627)  
    41. 729)  
    42. 269)  
    43. 188)  
    44. 3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)  
    45. 76)  
    46. 215)  
    47. 188)  
    48. 103)  
    49. 215)  
    50. 188)  
    51. 96)  
    52. 76)  
    53. 215)  
    54. 188)  
    55. 213)  
    56. 172)  
    57. 127)  
    58. 117)  
    59. 108)  
    60. 174)  
    61. 11.Http11Processor.process(Http11Processor.java:873)  
    62. 11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)  
    63. 528)  
    64. 81)  
    65. 689)  
    66. 619)  
    67. Caused by: java.sql.SQLException: Column 'id'
    68. 1072)  
    69. 986)  
    70. 981)  
    71. 926)  
    72. 1144)  
    73. 5616)  
    74. 41)  
    75. 184)  
    76. 210)  
    77. 497)  
    78. 443)  
    79. 340)  
    80. 629)  
    81. 724)  
    82. 259)  
    83. 2228)  
    84. 62


     

     

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

    所以我试试用JDBC连接




    1. public class
    2. public static void main(String[] args) throws
    3. "com.mysql.jdbc.Driver").newInstance();  
    4. "jdbc:mysql://localhost:3306/arms?useUnicode=true&characterEncoding=utf8&","root","");  
    5.            Statement stmt=con.createStatement();  
    6. "select id XXX_ID,name  from t_tab");  
    7. while(rs.next())  
    8.             {  
    9. "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里发现的这一段

     




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


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

    而不是 select id XXX_ID

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

     

     

     

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

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

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

     




    1. public void performDiscovery(Metadata metadata, List types, List aliases) throws
    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

     




    1. ResultSet rs=stmt.executeQuery(sql);  
    2.             ResultSetMetaData rsmd = rs.getMetaData();  
    3. int
    4. new
    5. for (int i = 1; i <= columnCount; i++) {  
    6. "___"
    7.                 System.out.println(tmp);  
    8. }


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

     

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

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

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

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

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

    com.mysql.jdbc.ResultSetMetaData

    中的

     




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

    修改为:

     




    1. public String getColumnName(int column) throws
    2. return
    3.     }


     

    然后把JDBC重新打包一下

     

    再运行就OK了.



    最佳解决方案:

     

    在jdbc.url中追加mysql参数 &useOldAliasMetadataBehavior=true 就可以解决。
    if (this.useOldAliasBehavior) { 
     return getField(column).getName(); 
     }

     


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

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

     

    查询方法是:




    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();


     


    错误信息:




      1. org.hibernate.exception.SQLGrammarException: could not execute query  
      2. 90)  
      3. 66)  
      4. 2231)  
      5. 2125)  
      6. 2120)  
      7. 312)  
      8. 1722)  
      9. 165)  
      10. 175)  
      11. 173)  
      12. 32)  
      13. 2d81000f.invoke(<generated>)  
      14. 149)  
      15. 2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)  
      16. 149)  
      17. 106)  
      18. 171)  
      19. 89)  
      20. 171)  
      21. 2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)  
      22. 1e3e6d9f.getList(<generated>)  
      23. 110)  
      24. 0(Native Method)  
      25. 39)  
      26. 25)  
      27. 597)  
      28. 269)  
      29. 170)  
      30. 110)  
      31. 58)  
      32. 67)  
      33. 51)  
      34. 191)  
      35. 305)  
      36. 191)  
      37. 283)  
      38. 1913)  
      39. 449)  
      40. 627)  
      41. 729)  
      42. 269)  
      43. 188)  
      44. 3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)  
      45. 76)  
      46. 215)  
      47. 188)  
      48. 103)  
      49. 215)  
      50. 188)  
      51. 96)  
      52. 76)  
      53. 215)  
      54. 188)  
      55. 213)  
      56. 172)  
      57. 127)  
      58. 117)  
      59. 108)  
      60. 174)  
      61. 11.Http11Processor.process(Http11Processor.java:873)  
      62. 11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)  
      63. 528)  
      64. 81)  
      65. 689)  
      66. 619)  
      67. Caused by: java.sql.SQLException: Column 'id'
      68. 1072)  
      69. 986)  
      70. 981)  
      71. 926)  
      72. 1144)  
      73. 5616)  
      74. 41)  
      75. 184)  
      76. 210)  
      77. 497)  
      78. 443)  
      79. 340)  
      80. 629)  
      81. 724)  
      82. 259)  
      83. 2228)  
      84. 62

       

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

      所以我试试用JDBC连接




      1. public class
      2. public static void main(String[] args) throws
      3. "com.mysql.jdbc.Driver").newInstance();  
      4. "jdbc:mysql://localhost:3306/arms?useUnicode=true&characterEncoding=utf8&","root","");  
      5.            Statement stmt=con.createStatement();  
      6. "select id XXX_ID,name  from t_tab");  
      7. while(rs.next())  
      8.             {  
      9. "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里发现的这一段

       




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



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

      而不是 select id XXX_ID

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

       

       

       

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

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

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

       



        1. public void performDiscovery(Metadata metadata, List types, List aliases) throws
        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

         



        1. ResultSet rs=stmt.executeQuery(sql);  
        2.             ResultSetMetaData rsmd = rs.getMetaData();  
        3. int
        4. new
        5. for (int i = 1; i <= columnCount; i++) {  
        6. "___"
        7.                 System.out.println(tmp);  
        8. }


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

         

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

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

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

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

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

        com.mysql.jdbc.ResultSetMetaData

        中的

         


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


        修改为:

         



        1. public String getColumnName(int column) throws
        2. return
        3.     }


         

        然后把JDBC重新打包一下

         

        再运行就OK了.

        举报

        相关推荐

        0 条评论