【踩坑实录】Hibernate报错node to traverse cannot be null排查

最近在改一份二手代码的时候,项目运行报了个java.lang.IllegalArgumentException: node to traverse cannot be null异常。
WTF?!难道我HQL写错了?!我只是添加了一个update方法而已啊!

问题排查:

clipboard.png
这里使用的是JPA的Query注解,其实语法跟HQL是一样的,我已经把这行HQL每个空格都TM检查过了,没有发现任何奇怪的东西,没办法了只好调试一下源码

clipboard.png
最先抛出异常的是在Hibernate的orghibernatehqlinternalastutilNodeTraverser.java:46,这里判断如果AST为空,则抛出异常,那AST到底是个啥啊?
clipboard.png
通过跟踪NodeTraverser的调用,可看到ACT是从parser获取的,而这里的parser实际上就是Hibernate的Hql语法分析器!因此网上很多文章都会得出本文提到的异常就是HQL语法错误导致的了。但是我这个HQL明显没有语法错误的,问题又出在哪呢?我们加个短点瞧一瞧:
clipboard.png

好玩的事情来了,如果HQL是select开头的话,是不会报错的

clipboard.png

等到一条update了,果然parser处理后的hqlAst是空的对比上面Select语句就可以明显看出问题所在了:问题出在了parser.statement()里,那跟进去看看囖:
clipboard.png
逐行调试,发现在执行updateStatement()时抛出异常,再跟进去:
clipboard.png
跑到default去了

clipboard.png
因为LA(1)是41,不在switch的任何分支里,然后实际上我在这花了很多时间,都浪费在看antrl的源码上了,就是想搞明白LA是在那里设值的,结果越看越懵逼,但实际上我们可以换个思路,通过监控每一步执行后的各个变量可以发现有这样的规律:

clipboard.png
上图是在执行match(UPDATE)前,各个主要变量如图所示

clipboard.png
直到执行了match方法后,LA(1)变为了41,而同时,LT(1)里的值引起了我的注意:
上面已经提到过了,实际上这部分代码是Hibernate的HQL语法解析器,那讲道理的话,第一次执行,处理完UPDATE关键字,往后应该是第二个关键字,而实际上我们的HQL中根被没有order这个词啊,为什么会导致报错呢?
还记得上面的某个断点么,就是调用parser.statement()的地方,来看看交由parser处理时的hql是什么样子的

clipboard.png
你们发现问题了吗?Hibernate在处理hql的时候,是会把包名补全的,而这个实体类的包名是以order开头的!update关键字后不能有order关键字...

最后我把实体类的包重构了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值