標籤:
在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 ); } } } }
解決Hibernate不支援PostgreSQL中雙冒號(::)的Bug