×
文章路径: Java

hql,jpql变量占位符不能出现.

发表于2年前(May 19, 2016 8:27:55 AM)  阅读 874  评论 0

分类: Java

标签: hql jpql 占位符 Unresolved property path unexpected AST node

hql,即hibernate query language,使用面向对象的方式书写sql语句,jpql,Java Persistence Query Language,主要用于jpa,而hibernate是jpa的一种实现,所以其实hql也可以说是jpql的一种实现,两者用法基本一致。

为了避免直接拼写hql,造成sql注入,我们写hql的时候,必须使用绑定变量的方式进行赋值。hql绑定变量有两种方式,一种是使用"?"占位符,根据"?"出现的顺序,提供参数,一种是使用变量名称的方式绑定。两种方式的示例:

String hql = "from Person p where p.id=?";
String hql = "from Person p where p.id=:id";

两种方式各有优势,都有相应地使用场景。

笔者要在这提的是变量绑定时需要注意的一个问题,如果变量里面包含".",将会出现hql解析报错,无法执行的情况,再看下面这么一个例子:

String hql = "from Menu e where e.parent.id=:parent.id order by sort";

可以看到,变量占位符使用了parent.id,中间包含了".",这时会出现如下错误:

2016-05-18 12:46:26.156 DEBUG [ErrorCounter.java:91] throwQueryException() : no errors
2016-05-18 12:46:26.157 DEBUG [HqlSqlBaseWalker.java:111] select << begin [level=1, statement=select]
2016-05-18 12:46:26.159 DEBUG [FromElement.java:157] FromClause{level=1} :  com.cangzhitao.admin.menu.domain.Menu (e) -> menu0_
2016-05-18 12:46:26.160 DEBUG [FromReferenceNode.java:74] Resolved :  e -> menu0_.id
2016-05-18 12:46:26.162 DEBUG [DotNode.java:613] getDataType() : parent -> org.hibernate.type.ManyToOneType(com.cangzhitao.admin.menu.domain.Menu)
2016-05-18 12:46:26.164 DEBUG [DotNode.java:570] dereferenceShortcut() : property id in com.cangzhitao.admin.menu.domain.Menu does not require a join.
2016-05-18 12:46:26.165 DEBUG [DotNode.java:594] Unresolved property path is now 'parent.id'
2016-05-18 12:46:26.166 DEBUG [FromReferenceNode.java:74] Resolved :  e.parent -> menu0_.parent
2016-05-18 12:46:26.167 DEBUG [DotNode.java:613] getDataType() : parent.id -> org.hibernate.type.LongType@7e17ac35
2016-05-18 12:46:26.167 DEBUG [FromReferenceNode.java:74] Resolved :  e.parent.id -> menu0_.parent
2016-05-18 12:46:26.171 ERROR [ErrorCounter.java:56] <AST>:1:64: unexpected AST node: :
2016-05-18 12:46:26.172 DEBUG [ErrorCounter.java:51] <AST>:1:64: unexpected AST node: :
<AST>:1:64: unexpected AST node: :
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.addrExpr(HqlSqlBaseWalker.java:4846)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.addrExprLhs(HqlSqlBaseWalker.java:5300)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.addrExpr(HqlSqlBaseWalker.java:4759)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1326)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4471)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:3947)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2047)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:831)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:617)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:301)
	at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:244)
	at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:254)
	at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:185)
	at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
	at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
	at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
	at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:124)
	at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156)
	at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:135)
	at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1770)
	at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:272)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
仔细分析,可以看到这么一句:Unresolved property path is now 'parent.id',说得还算是明白了吧,就是parent.id这个变量出了问题。去掉变量占位符中的"."就执行成功了,如改成"_":

String hql = "from Menu e where e.parent.id=:parent_id order by sort";

所以使用变量占位符的时候不要包含".",当然,不排除还有替他特殊字符,其实一般不会包含特殊字符,笔者这里出现"."也是因为框架里面通用方法的定义,将变量占位符直接使用变量名替代,才发现这个问题。

发表评论