解决Hibernate native sql中双冒号(:)转义的问题

来源:互联网 发布:mmd格斗动作数据下载 编辑:程序博客网 时间:2024/05/16 13:59

最近在做一个签到的任务,由于要查询到历史连续最大签到记录的值,起初还是有点迷茫的--有一种想将查询结果查询出来,然后使用算法来解决这个问题。但是折腾了半天,感觉有点难以处理,所以就google了一下和“签到”类似的处理方法,最终参考别人的实现是通过数据库来实现的,具体怎么处理这里不过多介绍了,文章结尾会将链接贴上。

回归到我需要讲解的问题--使用Hibernate 时,native sql中包含冒号(:),由于冒号在hibernate中是一个特殊的符号,用来标识预编译参数变量的.为何我会这么纠结呢,因为我们的系统定位的dao层就是使用Hibernate,所以我只好寻求能够处理好的方式(虽然我知道可以用spring jdbc来分分钟就可以实现),下面看下我初始的sql语句(看不懂也没有关系):


貌似上面的sql语句马上就可以大功告成了,因为我在sqlyog中直接复制进去可以直接将查询结果查询出来,但是当程序跑起来的时候,后台直接抛出一个异常:’Space is not allowed after parameter prefix ':' ‘。

此时,小哥我的内心是崩溃的,问了下度娘,把hibernate的源码找了出来---org.hibernate.engine.query.spi.ParameterParser

public static void parse(String sqlString, Recognizer recognizer) throws QueryException {final boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString );boolean foundMainOutputParam = false;final int stringLength = sqlString.length();boolean inQuote = false;for ( int indx = 0; indx < stringLength; indx++ ) {final 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 literalrecognizer.other( sqlString.charAt( ++indx ) );}else {if ( c == ':' ) {<span style="background-color: rgb(153, 255, 153);">// named parameter--就是这段代码的处理导致的final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 );final int chopLocation = right < 0 ? sqlString.length() : right;final 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;</span>}else if ( c == '?' ) {// could be either an ordinal or JPA-positional parameterif ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {// a peek ahead showed this as an JPA-positional parameterfinal int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );final int chopLocation = right < 0 ? sqlString.length() : right;final String param = sqlString.substring( indx + 1, chopLocation );// make sure this "name" is an integraltry {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中双冒号(::)的问题 ,别人是两个冒号,看了下博客的评论,有的小伙伴说可以直接用反斜杠来进行转义,抱着一种将信将疑的态度试了一下,sql如下:

真的是成功了,幸好没有用复杂的方式去解决问题(重写hibernate)。

用hibernate也有几年了,没想到真的是too young too simple ,此博客也希望能给自己的成长留下一个脚印。


最后,文章中说道的签到类型任务的处理实现参考如下(貌似要翻墙哦):

http://blog.itpub.net/29254281/cid-166562-list-1/

0 0
原创粉丝点击