在PostgreSQL中,双冒号(::)的作用是类型转换,而在Hibernate中,SQL中冒号的作用是命名参数,用于SQL中命名参数的匹配,这时,当在PostgreSQL数据库环境中,正常的SQL本身包括双冒号时,通过Hibernate进行查询就会报错,这个应该是Hibernate的一个Bug,怎么解决呢,本文将给出方案。
通过研究Hibernate的源代码,发现了问题所在,问题出在org.hibernate.engine.query.spi.ParameterParser,这个类构造方法为私有,包括若干个静态方法,无法通过扩展二次开发的方式解决,遇到这个问题的,只能自行修改Hibernate的源代码,然后编译。
经过分析,只需要修改其中的parse方法即可,下面的代码即为修改后的代码,测试了一下,大体应该是没问题的,该问题的发现、开发、测试是在Hibernate4.2.15版本下进行的,其他版本如有问题,请开发者自行处理。
public static void parse(String sqlString, Recognizer recognizer) throws QueryException { boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString ); boolean foundMainOutputParam = false; int stringLength = sqlString.length(); boolean inQuote = false; for ( int indx = 0; indx < stringLength; indx++ ) { char c = sqlString.charAt( indx ); if ( inQuote ) { if ( ‘\‘‘ == c ) { inQuote = false; } recognizer.other( c ); } else if ( ‘\‘‘ == c ) { inQuote = true; recognizer.other( c ); } else if ( ‘\\‘ == c ) { // skip sending the backslash and instead send then next character, treating is as a literal recognizer.other( sqlString.charAt( ++indx ) ); } else { if ( c == ‘:‘ ) { // named parameter int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 ); int chopLocation = right < 0 ? sqlString.length() : right; //增加了双冒号的处理 if (sqlString.charAt( indx+1 ) != ‘:‘){ String param = sqlString.substring( indx + 1, chopLocation ); if ( StringHelper.isEmpty( param ) ) { throw new QueryException( "Space is not allowed after parameter prefix ‘:‘ [" + sqlString + "]" ); } recognizer.namedParameter( param, indx ); indx = chopLocation - 1; }else{ recognizer.other(c); recognizer.other(c); indx++; } } else if ( c == ‘?‘ ) { // could be either an ordinal or JPA-positional parameter if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) { // a peek ahead showed this as an JPA-positional parameter int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 ); int chopLocation = right < 0 ? sqlString.length() : right; String param = sqlString.substring( indx + 1, chopLocation ); // make sure this "name" is an integral try { Integer.valueOf( param ); } catch( NumberFormatException e ) { throw new QueryException( "JPA-style positional param was not an integral ordinal" ); } recognizer.jpaPositionalParameter( param, indx ); indx = chopLocation - 1; } else { if ( hasMainOutputParameter && !foundMainOutputParam ) { foundMainOutputParam = true; recognizer.outParameter( indx ); } else { recognizer.ordinalParameter( indx ); } } } else { recognizer.other( c ); } } } }
时间: 2024-11-05 19:48:42