You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate执行HQL更新查询时ClassCastException问题排查

Hibernate Kotlin应用中执行HQL更新查询时的ClassCastException问题

错误信息

java.lang.ClassCastException: class org.hibernate.hql.internal.ast.tree.SqlNode cannot be cast to class org.hibernate.hql.internal.ast.tree.FromReferenceNode (org.hibernate.hql.internal.ast.tree.SqlNode and org.hibernate.hql.internal.ast.tree.FromReferenceNode are in unnamed module of loader 'app')
        at org.hibernate.hql.internal.ast.HqlSqlWalker.generateSyntheticDotNodeForNonQualifiedPropertyRef(HqlSqlWalker.java:747)
        at org.hibernate.hql.internal.ast.HqlSqlWalker.lookupNonQualifiedProperty(HqlSqlWalker.java:740)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.propertyRef(HqlSqlBaseWalker.java:1181)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.assignment(HqlSqlBaseWalker.java:1066)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.setClause(HqlSqlBaseWalker.java:782)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.java:398)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:286)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144)
        at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113)
        at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73)
        at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162)
        at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:622)
        at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:734)
        at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:23)
        at jp.assasans.protanki.server.quests.ServerDailyQuest$updateProgress$2$1.invokeSuspend(ServerDailyQuest.kt:48)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

问题场景

在基于Hibernate的Kotlin应用中,对抽象实体类ServerDailyQuest执行HQL更新查询时触发上述异常,相关代码如下:

实体类定义

package server.quests

import jakarta.persistence.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import server.HibernateUtils
import server.client.User
import server.extensions.singleOrNullOrThrow
import server.utils.LocalizedString

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(
  name = "daily_quests",
  indexes = [
    Index(name = "idx_daily_quests_user", columnList = "user_id")
  ]
)
abstract class ServerDailyQuest(
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  val id: Int,

  @ManyToOne
  val user: User,
  @Column(nullable = false, name = "questIndex") val index: Int, // INDEX是MariaDB的保留字

  @Column(nullable = false) var current: Int,
  @Column(nullable = false) var required: Int,

  @Column(nullable = false) var new: Boolean,
  @Column(nullable = false) var completed: Boolean,

  @OneToMany(targetEntity = ServerDailyQuestReward::class, mappedBy = "id.quest")
  val rewards: MutableList<ServerDailyQuestReward>
) {
  @get:Transient
  abstract val description: LocalizedString

  suspend fun updateProgress() {
    HibernateUtils.createEntityManager().let { entityManager ->
      entityManager.transaction.begin()

      withContext(Dispatchers.IO) {
          val queryString = "UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id"

          entityManager
              .createQuery(queryString)
              .setParameter("current", current)
              .setParameter("id", id)
              .setParameter("new", new)
              .setParameter("completed", completed)
              .executeUpdate()
      }

      entityManager.transaction.commit()
      entityManager.close()
    }
  }
}

触发异常的核心代码

val queryString = "UPDATE ServerDailyQuest SET current = :current, new = :new, completed = :completed WHERE id = :id"
entityManager.createQuery(queryString)

问题原因

HQL中的new是保留关键字,实体类中定义的属性名new与该关键字冲突,导致Hibernate在解析HQL语句时无法正确识别这是一个实体属性,进而触发类型转换异常。

解决方案

有两种可行的解决方式:

方式一:转义HQL中的属性名

在HQL里用反引号(`)包裹冲突的属性名,明确告诉Hibernate这是一个实体属性而非关键字:

val queryString = "UPDATE ServerDailyQuest SET current = :current, `new` = :new, completed = :completed WHERE id = :id"

方式二:修改实体类属性名

将实体类中的new属性名改为非关键字名称,比如isNew,如果需要保持数据库列名不变,可以通过@Column注解指定:

@Column(nullable = false, name = "new") var isNew: Boolean,

对应的HQL更新语句和参数设置也需要同步修改:

val queryString = "UPDATE ServerDailyQuest SET current = :current, isNew = :isNew, completed = :completed WHERE id = :id"
// 参数设置部分
.setParameter("isNew", isNew)

内容的提问来源于stack exchange,提问作者Misteriumbr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 08:04:59