Hibernate中如何修复命名查询错误(意外标记:DAY)?
搞定Hibernate命名查询的
unexpected token: DAY异常 嘿,我来帮你解决这个Hibernate编译报错的问题!
为啥会报错?
你写的查询里用了MySQL专属的DATE_SUB(current_date(), INTERVAL (:noofdays) DAY)语法,但HQL(Hibernate自己的查询语言)不买MySQL的账,它有自己的日期函数规则,直接用原生MySQL语法会导致解析失败,所以才会抛出unexpected token: DAY的错误。
给你几个靠谱的修复方案:
方案1:改用HQL支持的日期函数
HQL有标准的dateadd()函数,我们可以用它来实现“减去指定天数”的效果——只要把增量值设为负数就行:
DELETE FROM PAActivity pa WHERE pa.status IN (:statusSet) AND cast(pa.datoFinish as date) < dateadd('day', -:noofdays, current_date())
这里dateadd的参数顺序是「时间单位、增减量、基准日期」,用-:noofdays就相当于从当前日期往回推指定天数啦。
方案2:代码里先算好日期,直接传参数
我个人更推荐这个方法,简单直观还不挑数据库:先在Java代码里算出你要的阈值日期(比如90天前),再把这个日期作为参数传给查询。
比如Java 8+可以这么写:
LocalDate thresholdDate = LocalDate.now().minusDays(noofdays); // 然后把thresholdDate设为查询参数 query.setParameter("thresholdDate", thresholdDate);
对应的HQL就简化成这样:
DELETE FROM PAActivity pa WHERE pa.status IN (:statusSet) AND cast(pa.datoFinish as date) < :thresholdDate
这样完全避开了HQL和数据库语法的兼容性问题,维护起来也省心。
方案3:直接用原生SQL查询
如果你非要用MySQL的原生语法,那可以把这个查询声明为原生SQL,而不是HQL。比如用注解的话:
@NamedNativeQuery( name = "deleteOldActivities", query = "DELETE FROM PAActivity pa WHERE pa.status IN (:statusSet) AND cast(pa.datoFinish as date) < cast(DATE_SUB(current_date(), INTERVAL (:noofdays) DAY) as date)", resultClass = PAActivity.class )
或者在调用的时候用createNativeQuery方法,而不是普通的createQuery。不过这种方式会让代码和MySQL绑定,换数据库的话就得改查询,要慎重哦。
小建议
优先选方案2,代码层面处理日期逻辑,减少依赖;如果想用HQL的话就选方案1,兼容性更好;方案3只适合必须用数据库特定功能的场景。
内容的提问来源于stack exchange,提问作者fatherazrael
相关产品推荐
相关产品推荐

